diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index c5e6a903f..082bf4b71 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -1,4 +1,4 @@ -name: build +name: build_test on: push: @@ -7,7 +7,7 @@ on: branches: [ main ] jobs: - build: + build_test: timeout-minutes: 30 strategy: matrix: @@ -27,5 +27,11 @@ jobs: - uses: actions/checkout@v2 - name: Build run: swift build -v - - name: Run tests + - name: Run tests with Node.js run: swift test -v + - name: Install jsvu + run: npm install jsvu -g + - name: Install d8 + run: jsvu --os=default --engines=v8 + - name: Run tests with d8 + run: FUZZILLI_TEST_SHELL=~/.jsvu/engines/v8/v8 swift test -v diff --git a/Tests/FuzzilliTests/LiveTests.swift b/Tests/FuzzilliTests/LiveTests.swift index 6a1e467aa..8854c52ef 100644 --- a/Tests/FuzzilliTests/LiveTests.swift +++ b/Tests/FuzzilliTests/LiveTests.swift @@ -24,6 +24,29 @@ class LiveTests: XCTestCase { // Set to true to log failing programs static let VERBOSE = false + /// Meta-test ensuring that the test framework can successfully terminate an endless loop. + func testEndlessLoopTermination() throws { + let runner = try GetJavaScriptExecutorOrSkipTest() + + let results = try Self.runLiveTest(iterations: 1, withRunner: runner, timeoutInSeconds: 1) { b in + b.loadInt(123) // prefix + + let module = b.buildWasmModule() { module in + module.addWasmFunction(with: [] => []) { function, label, args in + function.wasmBuildLoop(with: [] => [], args: []) { label, args in + function.wasmBranch(to: label) + return [] + } + return [] + } + } + b.callMethod(module.getExportedMethod(at: 0), on: module.loadExports(), withArgs: []) + } + assert(results.failureRate == 1) + assert(results.failureMessages.count == 1) + print(results.failureMessages) + } + func testValueGeneration() throws { let runner = try GetJavaScriptExecutorOrSkipTest() @@ -142,7 +165,7 @@ class LiveTests: XCTestCase { // The closure can use the ProgramBuilder to emit a program of a specific // shape that is then executed with the given runner. We then check that // we stay below the maximum failure rate over the given number of iterations. - static func runLiveTest(iterations n: Int = 250, withRunner runner: JavaScriptExecutor, body: (ProgramBuilder) -> Void) throws -> (failureRate: Double, failureMessages: [String: Int]) { + static func runLiveTest(iterations n: Int = 250, withRunner runner: JavaScriptExecutor, timeoutInSeconds: Int = 5, body: (ProgramBuilder) -> Void) throws -> (failureRate: Double, failureMessages: [String: Int]) { let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) // We have to use the proper JavaScriptEnvironment here. @@ -178,7 +201,7 @@ class LiveTests: XCTestCase { } DispatchQueue.concurrentPerform(iterations: n) { i in - let result = executeAndParseResults(program: programs[i], runner: runner) + let result = executeAndParseResults(program: programs[i], runner: runner, timeoutInSeconds: timeoutInSeconds) results[i] = result } @@ -214,10 +237,11 @@ class LiveTests: XCTestCase { } } - static func executeAndParseResults(program: (program: Program, jsProgram: String), runner: JavaScriptExecutor) -> ExecutionResult { + static func executeAndParseResults(program: (program: Program, jsProgram: String), runner: JavaScriptExecutor, timeoutInSeconds: Int) -> ExecutionResult { do { - let result = try runner.executeScript(program.jsProgram, withTimeout: 5 * Seconds) + let result = try runner.executeScript(program.jsProgram, + withTimeout: Double(timeoutInSeconds) * Seconds) if result.isFailure { var signature: String? = nil