Commit 34c7f54d authored by hongchan@chromium.org's avatar hongchan@chromium.org

This patch includes a fix and refactoring on several layout tests for promise...

This patch includes a fix and refactoring on several layout tests for promise from AudioContext.suspend() and .resume().

|Audit| task runner handles the sequential execution of asynchrous test tasks.

BUG=460504

Review URL: https://codereview.chromium.org/945023002

git-svn-id: svn://svn.chromium.org/blink/trunk@190694 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent f482d402
...@@ -28,13 +28,13 @@ PASS context.createWaveShaper() threw exception InvalidStateError: Failed to exe ...@@ -28,13 +28,13 @@ PASS context.createWaveShaper() threw exception InvalidStateError: Failed to exe
PASS osc.connect(gain) threw exception InvalidStateError: Failed to execute 'connect' on 'AudioNode': Cannot connect after the context has been closed.. PASS osc.connect(gain) threw exception InvalidStateError: Failed to execute 'connect' on 'AudioNode': Cannot connect after the context has been closed..
PASS gain.disconnect() did not throw exception. PASS gain.disconnect() did not throw exception.
PASS Attempt to resume a closed context was correctly rejected PASS Attempt to resume a closed context was correctly rejected
PASS Closing context again correctly rejected promise.
PASS offline = new OfflineAudioContext(1, 1000, 48000) did not throw exception. PASS offline = new OfflineAudioContext(1, 1000, 48000) did not throw exception.
PASS offline.state is "suspended" PASS offline.state is "suspended"
PASS Closing offline context correctly rejected PASS Closing offline context correctly rejected
PASS Closing context again correctly rejected promise.
PASS Closing offline context again correctly rejected PASS Closing offline context again correctly rejected
PASS offline.startRendering() did not throw exception. PASS offline.startRendering() did not throw exception.
PASS offline.state is "closed" PASS event.target.state is "closed"
PASS successfullyParsed is true PASS successfullyParsed is true
TEST COMPLETE TEST COMPLETE
......
<!doctype html> <!doctype html>
<html> <html>
<head> <head>
<title>Test AudioContext.close()</title> <title>Test AudioContext.close()</title>
<script src="../resources/js-test.js"></script>
<script src="resources/compatibility.js"></script> <script src="resources/compatibility.js"></script>
<script src="resources/audio-testing.js"></script> <script src="resources/audio-testing.js"></script>
<script src="../resources/js-test.js"></script> </head>
</head>
<body> <body>
<script> <script>
description("Basic functionality test of closing an AudioContext"); description("Basic functionality test of closing an AudioContext");
window.jsTestIsAsync = true;
var context; var context;
var offline; var offline;
...@@ -20,14 +21,13 @@ ...@@ -20,14 +21,13 @@
var offlinePromise; var offlinePromise;
var wave = new Float32Array(1); var wave = new Float32Array(1);
var audit = Audit.createTaskRunner();
function runTest() { // Task: test online context (1).
window.jsTestIsAsync = true; audit.defineTask('test-online-context-1', function (done) {
runOnlineTest();
}
function runOnlineTest() { // Create a context and verify that the various states are correct and
// Create a context and verify that the various states are correct and that close() exists. // that close() exists.
shouldNotThrow("context = new AudioContext()"); shouldNotThrow("context = new AudioContext()");
shouldBeEqualToString("context.state", "running"); shouldBeEqualToString("context.state", "running");
...@@ -36,27 +36,33 @@ ...@@ -36,27 +36,33 @@
shouldNotThrow("gain = context.createGain()"); shouldNotThrow("gain = context.createGain()");
shouldNotThrow("gain.connect(context.destination)"); shouldNotThrow("gain.connect(context.destination)");
// Close the context. When the promise is resolved, continue online testing, and then run // Close the context. When the promise is resolved, continue the next
// the offline tests. // test task.
context.close() context.close().then(
.then(function () { function () {
testPassed("context.close() was correctly resolved"); testPassed("context.close() was correctly resolved");
continueOnlineTest();
}, },
function () { function () {
testFailed("context.close() was erroneously rejected"); testFailed("context.close() was erroneously rejected");
})
.then(runOfflineTest);
} }
).then(done);
});
function continueOnlineTest() { // Task: test online context (2).
// Context is released, so verify that we cannot create any more nodes, nor connect any. audit.defineTask('test-online-context-2', function (done) {
// Context is closed, so verify that we cannot create any more nodes,
// nor connect any.
shouldThrow("context.createAnalyser()"); shouldThrow("context.createAnalyser()");
shouldThrow("context.createBiquadFilter()"); shouldThrow("context.createBiquadFilter()");
// createBuffer is an exception because it's not really tied in any way to an audio
// context. And it's useful to be able to create a buffer inside the oncomplete event of an // createBuffer is an exception because it's not really tied in any way
// offline context to use for testing purposes. // to an audio context. And it's useful to be able to create a buffer
// inside the oncomplete event of an offline context to use for testing
// purposes.
shouldNotThrow("context.createBuffer(1, 1, 48000)"); shouldNotThrow("context.createBuffer(1, 1, 48000)");
shouldThrow("context.createBufferSource()"); shouldThrow("context.createBufferSource()");
shouldThrow("context.createChannelMerger()"); shouldThrow("context.createChannelMerger()");
shouldThrow("context.createChannelSplitter()"); shouldThrow("context.createChannelSplitter()");
...@@ -75,26 +81,29 @@ ...@@ -75,26 +81,29 @@
shouldNotThrow("gain.disconnect()"); shouldNotThrow("gain.disconnect()");
// Can't resume a context that is closed (released). // Can't resume a context that is closed (released).
context.resume() context.resume().then(
.then(function () { function () {
testFailed("Attempt to resume a closed context erroneously succeeded"); testFailed("Attempt to resume a closed context erroneously succeeded");
}, },
function () { function () {
testPassed("Attempt to resume a closed context was correctly rejected"); testPassed("Attempt to resume a closed context was correctly rejected");
})
.then(continueOnlineTest2);
} }
).then(done);
});
// Task: test online context (3).
audit.defineTask('test-online-context-3', function (done) {
function continueOnlineTest2() {
// Try closing the context again. The promise should be rejected. // Try closing the context again. The promise should be rejected.
context.close() context.close().then(
.then(function () { function () {
testFailed("Closing context again erroneously resolved successfully."); testFailed("Closing context again erroneously resolved successfully.");
}, },
function () { function () {
testPassed("Closing context again correctly rejected promise."); testPassed("Closing context again correctly rejected promise.");
// Finally, run GC. The context should be gone, but this seems difficult to verify.
// Finally, run GC. The context should be gone, but this seems
// difficult to verify.
if (window.hasOwnProperty('GCController')) { if (window.hasOwnProperty('GCController')) {
asyncGC(function () { asyncGC(function () {
shouldBeNull("context.destination"); shouldBeNull("context.destination");
...@@ -103,44 +112,67 @@ ...@@ -103,44 +112,67 @@
shouldBeNull("context.destination"); shouldBeNull("context.destination");
testFailed("asyncGC test not run"); testFailed("asyncGC test not run");
} }
});
} }
).then(done);
});
function runOfflineTest () { // Task: test offline context (1).
// For an offline context, just check that if we try to close the context, nothing happens audit.defineTask('test-offline-context-1', function (done) {
// except that the promise returned by close() is rejected.
// For an offline context, just check that if we try to close the context,
// nothing happens except that the promise returned by close() is rejected.
shouldNotThrow("offline = new OfflineAudioContext(1, 1000, 48000)"); shouldNotThrow("offline = new OfflineAudioContext(1, 1000, 48000)");
shouldBeEqualToString("offline.state", "suspended"); shouldBeEqualToString("offline.state", "suspended");
offline.close() offline.close().then(
.then(function () { function () {
testFailed("Closing offline context erroneously resolved"); testFailed("Closing offline context erroneously resolved");
}, },
function () { function () {
testPassed("Closing offline context correctly rejected"); testPassed("Closing offline context correctly rejected");
})
.then(continueOfflineTest);
} }
).then(done);
});
// Task: test offline context (2).
audit.defineTask('test-offline-context-2', function (done) {
function continueOfflineTest () {
// Try closing again // Try closing again
offline.close() offline.close().then(
.then(function () { function () {
testFailed("Closing offline context again erroneously resolved"); testFailed("Closing offline context again erroneously resolved");
}, function () { },
function () {
testPassed("Closing offline context again correctly rejected"); testPassed("Closing offline context again correctly rejected");
}) }
.then(function () { ).then(
function () {
// Render the context, and check for a valid state // Render the context, and check for a valid state
offline.oncomplete = function (event) { offline.oncomplete = function (event) {
shouldBeEqualToString("offline.state", "closed"); shouldBeEqualToString("event.target.state", "closed");
finishJSTest(); done();
}; };
shouldNotThrow("offline.startRendering()"); shouldNotThrow("offline.startRendering()");
});
} }
);
});
audit.defineTask('finish-test', function (done) {
done();
finishJSTest();
});
audit.runTasks(
'test-online-context-1',
'test-online-context-2',
'test-online-context-3',
'test-offline-context-1',
'test-offline-context-2',
'finish-test'
);
runTest();
successfullyParsed = true; successfullyParsed = true;
</script> </script>
</body> </body>
</html> </html>
...@@ -7,7 +7,7 @@ PASS context.state is "suspended" ...@@ -7,7 +7,7 @@ PASS context.state is "suspended"
PASS p1 = context.suspend() did not throw exception. PASS p1 = context.suspend() did not throw exception.
PASS [object Object] is an instance of function Promise() { [native code] } PASS [object Object] is an instance of function Promise() { [native code] }
PASS context.suspend() was correctly rejected for an offline context PASS context.suspend() was correctly rejected for an offline context
PASS p1 = context.resume() did not throw exception. PASS p2 = context.resume() did not throw exception.
PASS [object Object] is an instance of function Promise() { [native code] } PASS [object Object] is an instance of function Promise() { [native code] }
PASS context.state is "suspended" PASS context.state is "suspended"
PASS context.resume() was correctly rejected for an offline context PASS context.resume() was correctly rejected for an offline context
......
<!doctype html> <!doctype html>
<html> <html>
<head> <head>
<title>Test audiocontext suspend/resume</title> <title>Test AudioContext.suspend() and AudioContext.resume()</title>
<script src="../resources/js-test.js"></script>
<script src="resources/compatibility.js"></script> <script src="resources/compatibility.js"></script>
<script src="resources/audio-testing.js"></script> <script src="resources/audio-testing.js"></script>
<script src="../resources/js-test.js"></script> </head>
</head>
<body> <body>
<script> <script>
description("Test suspend/resume for an (offline) AudioContext"); description("Test suspend/resume for an (offline) AudioContext");
window.jsTestIsAsync = true;
var context; var context;
var osc; var osc;
...@@ -19,68 +20,25 @@ ...@@ -19,68 +20,25 @@
var sampleRate = 44100; var sampleRate = 44100;
var durationInSeconds = 1; var durationInSeconds = 1;
// Convenience function that returns a function that calls the |passFailMethod| with the given var audit = Audit.createTaskRunner();
// |message|. The |passFailMethod| should be either |testPassed| or |testFailed|.
function handlePromise(passFailMethod, message) { // Convenience function that returns a function that calls the |passFailFunc|
// with the given |message|. The |passFailFunc| should be either |testPassed|
// or |testFailed|.
function handlePromise(passFailFunc, message) {
return function () { return function () {
passFailMethod(message); passFailFunc(message);
}; };
} }
function checkResult (event) { // Task: test suspend().
// We don't care about the actual result of the offline rendering. audit.defineTask('test-suspend', function (done) {
shouldBeEqualToString("context.state", "closed");
// suspend() should be rejected on a closed context.
context.suspend()
.then(handlePromise(
testFailed,
"context.suspend() on a closed context not rejected"),
handlePromise(
testPassed,
"context.suspend() on a closed context rejected as expected"))
.then(function () {
// resume() should be rejected on closed context.
return context.resume();
})
.then(handlePromise(
testFailed,
"context.resume() on a closed context not rejected"),
handlePromise(
testPassed,
"context.resume() on a closed context rejected as expected"))
.then(finishJSTest);
}
function runOfflineContextTest() {
// Render the offline context.
osc.start();
context.oncomplete = checkResult;
context.startRendering();
}
function runResumeTest () {
// Multiple calls to resume should not be a problem. But we can't test that on an offline
// context. Thus, check that resume() on an OfflineAudioContext rejects the promise.
shouldNotThrow("p1 = context.resume()");
shouldBeType(p1, Promise);
// Resume doesn't actually resume an offline context
shouldBeEqualToString("context.state", "suspended");
p1.then(handlePromise(
testFailed,
"context.resume() should have been rejected for an offline context"),
handlePromise(
testPassed,
"context.resume() was correctly rejected for an offline context"))
.then(runOfflineContextTest);
}
function runTest() { // Test suspend/resume. Ideally this test is best with a online
window.jsTestIsAsync = true; // AudioContext, but content shell doesn't really have a working online
// Test suspend/resume. Ideally this test is best with a online AudioContext, but content // AudioContext. Hence, use an OfflineAudioContext. Not all possible
// shell doesn't really have a working online AudioContext. Hence, use an // scenarios can be easily checked with an offline context instead of an
// OfflineAudioContext. Not all possible scenarios can be easily checked with an offline // online context.
// context instead of an online context.
// Create an audio context with an oscillator. // Create an audio context with an oscillator.
context = new OfflineAudioContext(1, durationInSeconds * sampleRate, sampleRate); context = new OfflineAudioContext(1, durationInSeconds * sampleRate, sampleRate);
...@@ -90,21 +48,75 @@ ...@@ -90,21 +48,75 @@
// Verify the state. // Verify the state.
shouldBeEqualToString("context.state", "suspended"); shouldBeEqualToString("context.state", "suspended");
// Multiple calls to suspend() should not be a problem. But we can't test that on an offline // Multiple calls to suspend() should not be a problem. But we can't test
// context. Thus, check that suspend() on an OfflineAudioContext rejects the promise. // that on an offline context. Thus, check that suspend() on an
// OfflineAudioContext rejects the promise.
shouldNotThrow("p1 = context.suspend()"); shouldNotThrow("p1 = context.suspend()");
shouldBeType(p1, Promise); shouldBeType(p1, Promise);
p1.then(handlePromise( p1.then(
testFailed, handlePromise(testFailed, "context.suspend() should have been rejected for an offline context"),
"context.suspend() should have been rejected for an offline context"), handlePromise(testPassed, "context.suspend() was correctly rejected for an offline context")
handlePromise( ).then(done);
testPassed, });
"context.suspend() was correctly rejected for an offline context"))
.then(runResumeTest);
} // Task: test resume().
audit.defineTask('test-resume', function (done) {
// Multiple calls to resume should not be a problem. But we can't test
// that on an offline context. Thus, check that resume() on an
// OfflineAudioContext rejects the promise.
shouldNotThrow("p2 = context.resume()");
shouldBeType(p2, Promise);
// Resume doesn't actually resume an offline context
shouldBeEqualToString("context.state", "suspended");
p2.then(
handlePromise(testFailed, "context.resume() should have been rejected for an offline context"),
handlePromise(testPassed, "context.resume() was correctly rejected for an offline context")
).then(done);
});
// Task: test the state after context closed.
audit.defineTask('test-after-close', function (done) {
// Render the offline context.
osc.start();
// Test suspend/resume in tested promise pattern. We don't care about the
// actual result of the offline rendering.
context.startRendering().then(function () {
shouldBeEqualToString("context.state", "closed");
// suspend() should be rejected on a closed context.
context.suspend().then(
handlePromise(testFailed, "context.suspend() on a closed context not rejected"),
handlePromise(testPassed, "context.suspend() on a closed context rejected as expected")
).then(function () {
// resume() should be rejected on closed context.
context.resume().then(
handlePromise(testFailed, "context.resume() on a closed context not rejected"),
handlePromise(testPassed, "context.resume() on a closed context rejected as expected")
).then(done);
});
});
});
audit.defineTask('finish-test', function (done) {
done();
finishJSTest();
});
audit.runTasks(
'test-suspend',
'test-resume',
'test-after-close',
'finish-test'
);
runTest();
successfullyParsed = true; successfullyParsed = true;
</script> </script>
</body> </body>
</html> </html>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment