-
Notifications
You must be signed in to change notification settings - Fork 251
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(hit limit): infinite loop prevention in jasmine-runner (#3199)
Add infinite loop prevention using a hit counter to `@stryker-mutator/jasmine-runner`.
- Loading branch information
1 parent
134699e
commit bc792e0
Showing
18 changed files
with
253 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
{ | ||
"spec": "test/**.mocha.spec.js" | ||
"require": ["test/chai-setup.js"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"spec_dir": "spec", | ||
"spec_files": [ | ||
"../test/*.spec.js" | ||
], | ||
"stopSpecOnExpectationFailure": false, | ||
"random": true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
const chai = require('chai'); | ||
|
||
chai.util.addMethod(chai.Assertion.prototype, 'toEqual', function (expected) { | ||
var obj = chai.util.flag(this, 'object'); | ||
new chai.Assertion(obj).to.deep.equal(expected); | ||
}); |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
if (typeof require === 'function') { | ||
loop = require('../src/loop').loop; | ||
} | ||
if (typeof expect === 'undefined') { | ||
globalThis.expect = require('chai').expect; | ||
} | ||
|
||
describe('loop', () => { | ||
it('should result in 15 for n=5 and a sum function', () => { | ||
let result = 0; | ||
loop(5, (n) => (result += n)); | ||
expect(result).toEqual(15); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
56 changes: 56 additions & 0 deletions
56
packages/jasmine-runner/test/integration/timeout-on-infinite-loop.it.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { testInjector, factory, assertions } from '@stryker-mutator/test-helpers'; | ||
import { expect } from 'chai'; | ||
|
||
import { createJasmineTestRunnerFactory, JasmineTestRunner } from '../../src'; | ||
import { resolveFromRoot, resolveTestResource } from '../helpers/resolve-test-resource'; | ||
|
||
describe('Infinite loop', () => { | ||
let sut: JasmineTestRunner; | ||
|
||
beforeEach(async () => { | ||
process.chdir(resolveTestResource('infinite-loop-instrumented')); | ||
sut = testInjector.injector.injectFunction(createJasmineTestRunnerFactory('__stryker2__')); | ||
}); | ||
afterEach(async () => { | ||
process.chdir(resolveFromRoot()); | ||
await sut.dispose(); | ||
}); | ||
|
||
it('should be able to recover using a hit counter', async () => { | ||
// Arrange | ||
const options = factory.mutantRunOptions({ | ||
activeMutant: factory.mutant({ id: '19' }), | ||
testFilter: ['spec2'], | ||
hitLimit: 10, | ||
}); | ||
|
||
// Act | ||
const result = await sut.mutantRun(options); | ||
|
||
// Assert | ||
assertions.expectTimeout(result); | ||
expect(result.reason).contains('Hit limit reached'); | ||
}); | ||
|
||
it('should reset hit counter state correctly between runs', async () => { | ||
const firstResult = await sut.mutantRun( | ||
factory.mutantRunOptions({ | ||
activeMutant: factory.mutant({ id: '19' }), | ||
testFilter: ['spec2'], | ||
hitLimit: 10, | ||
}) | ||
); | ||
const secondResult = await sut.mutantRun( | ||
factory.mutantRunOptions({ | ||
// 27 is a 'normal' mutant that should be killed | ||
activeMutant: factory.mutant({ id: '22' }), | ||
testFilter: ['spec2'], | ||
hitLimit: 10, | ||
}) | ||
); | ||
|
||
// Assert | ||
assertions.expectTimeout(firstResult); | ||
assertions.expectKilled(secondResult); | ||
}); | ||
}); |
84 changes: 84 additions & 0 deletions
84
packages/jasmine-runner/testResources/infinite-loop-instrumented/lib/infinite-loop.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
// This file is generated with tasks/instrument-test-resources.js | ||
function stryNS_9fa48() { | ||
var g = new Function("return this")(); | ||
var ns = g.__stryker2__ || (g.__stryker2__ = {}); | ||
|
||
if (ns.activeMutant === undefined && g.process && g.process.env && g.process.env.__STRYKER_ACTIVE_MUTANT__) { | ||
ns.activeMutant = g.process.env.__STRYKER_ACTIVE_MUTANT__; | ||
} | ||
|
||
function retrieveNS() { | ||
return ns; | ||
} | ||
|
||
stryNS_9fa48 = retrieveNS; | ||
return retrieveNS(); | ||
} | ||
|
||
stryNS_9fa48(); | ||
|
||
function stryCov_9fa48() { | ||
var ns = stryNS_9fa48(); | ||
var cov = ns.mutantCoverage || (ns.mutantCoverage = { | ||
static: {}, | ||
perTest: {} | ||
}); | ||
|
||
function cover() { | ||
var c = cov.static; | ||
|
||
if (ns.currentTestId) { | ||
c = cov.perTest[ns.currentTestId] = cov.perTest[ns.currentTestId] || {}; | ||
} | ||
|
||
var a = arguments; | ||
|
||
for (var i = 0; i < a.length; i++) { | ||
c[a[i]] = (c[a[i]] || 0) + 1; | ||
} | ||
} | ||
|
||
stryCov_9fa48 = cover; | ||
cover.apply(null, arguments); | ||
} | ||
|
||
function stryMutAct_9fa48(id) { | ||
var ns = stryNS_9fa48(); | ||
|
||
function isActive(id) { | ||
if (ns.activeMutant === id) { | ||
if (ns.hitCount !== void 0 && ++ns.hitCount > ns.hitLimit) { | ||
throw new Error('Stryker: Hit count limit reached (' + ns.hitCount + ')'); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
stryMutAct_9fa48 = isActive; | ||
return isActive(id); | ||
} | ||
|
||
function loop(n, action) { | ||
if (stryMutAct_9fa48("15")) { | ||
{} | ||
} else { | ||
stryCov_9fa48("15"); | ||
let goOn = stryMutAct_9fa48("16") ? false : (stryCov_9fa48("16"), true); | ||
|
||
while (stryMutAct_9fa48("17") ? false : (stryCov_9fa48("17"), goOn)) { | ||
if (stryMutAct_9fa48("18")) { | ||
{} | ||
} else { | ||
stryCov_9fa48("18"); | ||
action(n); | ||
stryMutAct_9fa48("19") ? n++ : (stryCov_9fa48("19"), n--); | ||
goOn = stryMutAct_9fa48("23") ? n <= 0 : stryMutAct_9fa48("22") ? n >= 0 : stryMutAct_9fa48("21") ? false : stryMutAct_9fa48("20") ? true : (stryCov_9fa48("20", "21", "22", "23"), n > 0); | ||
} | ||
} | ||
} | ||
} | ||
|
||
module.exports = loop; |
11 changes: 11 additions & 0 deletions
11
packages/jasmine-runner/testResources/infinite-loop-instrumented/spec/support/jasmine.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"spec_dir": "spec", | ||
"spec_files": [ | ||
"**/*[sS]pec.js" | ||
], | ||
"helpers": [ | ||
"helpers/**/*.js" | ||
], | ||
"stopSpecOnExpectationFailure": false, | ||
"random": false | ||
} |
16 changes: 16 additions & 0 deletions
16
.../jasmine-runner/testResources/infinite-loop-instrumented/spec/tests/infinite-loop.spec.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
var loop = require('../../lib/infinite-loop'); | ||
|
||
it('should handle an infinite loop as a timeout', () => { | ||
while (true); | ||
}); | ||
|
||
it('should be able to recover and test others', () => {}); | ||
|
||
it('should be able to break out of an infinite loop with a hit counter', () => { | ||
let total = 0; | ||
loop(5, (n) => { | ||
expect(n).not.toBe(0); | ||
total += n; | ||
}); | ||
expect(total).toBe(15); | ||
}); |
10 changes: 10 additions & 0 deletions
10
packages/jasmine-runner/testResources/infinite-loop/lib/infinite-loop.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
function loop(n, action) { | ||
let goOn = true; | ||
while (goOn) { | ||
action(n); | ||
n--; | ||
goOn = n > 0; | ||
} | ||
} | ||
|
||
module.exports = loop; |
11 changes: 11 additions & 0 deletions
11
packages/jasmine-runner/testResources/infinite-loop/spec/support/jasmine.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"spec_dir": "spec", | ||
"spec_files": [ | ||
"**/*[sS]pec.js" | ||
], | ||
"helpers": [ | ||
"helpers/**/*.js" | ||
], | ||
"stopSpecOnExpectationFailure": false, | ||
"random": false | ||
} |
16 changes: 16 additions & 0 deletions
16
packages/jasmine-runner/testResources/infinite-loop/spec/tests/infinite-loop.spec.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
var loop = require('../../lib/infinite-loop'); | ||
|
||
it('should handle an infinite loop as a timeout', () => { | ||
while (true); | ||
}); | ||
|
||
it('should be able to recover and test others', () => {}); | ||
|
||
it('should be able to break out of an infinite loop with a hit counter', () => { | ||
let total = 0; | ||
loop(5, (n) => { | ||
expect(n).not.toBe(0); | ||
total += n; | ||
}); | ||
expect(total).toBe(15); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters