Commit 1353ccba authored by Makoto Shimazu's avatar Makoto Shimazu Committed by Commit Bot

Revert "Implemented headless compositor protocol tests for basic rAF, GIF and CSS animations."

This reverts commit 9cd2322d.

Reason for revert: This CL seems causing flaky timeouts of HeadlessProtocolBrowserTest.VirtualTimeErrorLoop.
https://test-results.appspot.com/dashboards/flakiness_dashboard.html#testType=headless_browsertests&tests=HeadlessProtocolBrowserTest.VirtualTimeErrorLoop%0A

Original change's description:
> Implemented headless compositor protocol tests for basic rAF, GIF and CSS animations.
> 
> Change-Id: I956ea3523eb42b6d7f0cf851a126c6a11578912e
> Reviewed-on: https://chromium-review.googlesource.com/1121378
> Commit-Queue: Peter Kvitek <kvitekp@chromium.org>
> Reviewed-by: Pavel Feldman <pfeldman@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#572253}

TBR=dgozman@chromium.org,pfeldman@chromium.org,kvitekp@chromium.org

Change-Id: I777f261f3d4a69ca15cdc4cb717ea485bc5308c4
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/1125480Reviewed-by: default avatarMakoto Shimazu <shimazu@chromium.org>
Commit-Queue: Makoto Shimazu <shimazu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#572467}
parent e68ef11a
......@@ -4,10 +4,5 @@ specific_include_rules = {
"+components/viz/common/features.h",
"+components/viz/common/switches.h",
"+third_party/skia/include",
],
"headless_protocol_browsertest.cc": [
"+cc/base/switches.h",
"+components/viz/common/features.h",
"+components/viz/common/switches.h",
]
}
Tests compositor basic rAF operation.
Advanced to 10ms
Advanced to 510ms
Advanced to 1000ms
Elasped time: 1000
Requesting first animation frame
Animation frame callback #1
Advanced to 1100ms
Elasped time: 1100
Animation frame callback #2
Advanced to 1200ms
Elasped time: 1200
Animation frame callback #3
Advanced to 1300ms
Elasped time: 1300
Animation frame callback #4
Advanced to 1400ms
Elasped time: 1400
Animation frame count: 4
Animation frame callback #5
Screenshot size: 800 x 600
Screenshot rgba: 0,0,50,255
\ No newline at end of file
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
(async function(testRunner) {
var {page, session, dp} = await testRunner.startBlank(
'Tests compositor basic rAF operation.');
await dp.Target.enable();
// Open the test page in a new tab with BeginFrameControl enabled.
await testTargetPage(await testRunner.createTargetInNewContext(
session, 800, 600, 'about:blank', true));
// This runs requestAnimationFrame five times without updating display then
// takes a screenshotin in a newly created tab with BeginFrame control.
async function testTargetPage(session) {
dp = session.protocol;
await dp.Runtime.enable();
await dp.HeadlessExperimental.enable();
dp.Runtime.onConsoleAPICalled(data => {
const text = data.params.args[0].value;
testRunner.log(text);
});
dp.Emulation.onVirtualTimeAdvanced(data => {
// Debug chrome schedules stray tasks that break this test.
// Our numbers are round, so we prevent this flake 999 times of 1000.
const time = data.params.virtualTimeElapsed;
if (time !== Math.round(time))
return;
testRunner.log(`Advanced to ${time}ms`);
});
let virtualTimeBase = 0;
let totalElapsedTime = 0;
let frameTimeTicks = 0;
let lastGrantedChunk = 0;
dp.Emulation.onVirtualTimePaused(data => {
// Remember the base time for frame time calculation.
virtualTimeBase = data.params.virtualTimeElapsed;
});
await dp.Emulation.setVirtualTimePolicy({policy: 'pause'});
lastGrantedChunk = 1000;
await dp.Emulation.setVirtualTimePolicy({
policy: 'pauseIfNetworkFetchesPending',
budget: lastGrantedChunk, waitForNavigation: true});
dp.Page.navigate(
{url: testRunner.url('/resources/compositor-basic-raf.html')});
// Renderer wants the very first frame to be fully updated.
await AdvanceTime();
await session.evaluate('startRAF()');
await dp.HeadlessExperimental.beginFrame({frameTimeTicks});
await GrantMoreTime(100);
// Send 3 updateless frames.
for (var n = 0; n < 3; ++n) {
await AdvanceTime();
await dp.HeadlessExperimental.beginFrame({frameTimeTicks,
noDisplayUpdates: true});
await GrantMoreTime(100);
}
// Grab screenshot, expected size 800x600, rgba: 0,0,50,255.
await AdvanceTime();
testRunner.log(await session.evaluate('displayRAFCount();'));
const screenshotData =
(await dp.HeadlessExperimental.beginFrame(
{frameTimeTicks, screenshot: {format: 'png'}}))
.result.screenshotData;
await logScreenShotInfo(screenshotData);
testRunner.completeTest();
async function AdvanceTime() {
await dp.Emulation.onceVirtualTimeBudgetExpired();
totalElapsedTime += lastGrantedChunk;
testRunner.log(`Elasped time: ${totalElapsedTime}`);
frameTimeTicks = virtualTimeBase + totalElapsedTime;
}
async function GrantMoreTime(budget) {
lastGrantedChunk = budget;
await dp.Emulation.setVirtualTimePolicy({
policy: 'pauseIfNetworkFetchesPending', budget});
}
function logScreenShotInfo(pngBase64) {
const image = new Image();
let callback;
let promise = new Promise(fulfill => callback = fulfill);
image.onload = function() {
testRunner.log(`Screenshot size: `
+ `${image.naturalWidth} x ${image.naturalHeight}`);
const canvas = document.createElement('canvas');
canvas.width = image.naturalWidth;
canvas.height = image.naturalHeight;
const ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0);
const rgba = ctx.getImageData(0, 0, 1, 1).data;
testRunner.log(`Screenshot rgba: ${rgba}`);
callback();
}
image.src = `data:image/png;base64,${pngBase64}`;
return promise;
}
}
})
Tests compositor animated css handling.
Expired count: 1, elaspedTime: 500
Expired count: 2, elaspedTime: 1000
Event [animationstart] at 0 sec
Screenshot rgba: 255,0,0,255
Expired count: 3, elaspedTime: 1500
Event [animationiteration] at 1 sec
Screenshot rgba: 1,0,254,255
Expired count: 4, elaspedTime: 2000
Expired count: 5, elaspedTime: 2500
Event [animationiteration] at 2 sec
Expired count: 6, elaspedTime: 3000
Expired count: 7, elaspedTime: 3500
Event [animationiteration] at 3 sec
Screenshot rgba: 1,0,254,255
Expired count: 8, elaspedTime: 4000
Screenshot rgba: 255,0,0,255
Expired count: 9, elaspedTime: 4500
Event [animationend] at 4 sec
Screenshot rgba: 0,0,255,255
Expired count: 10, elaspedTime: 5000
Screenshot rgba: 0,0,255,255
\ No newline at end of file
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
(async function(testRunner) {
var {page, session, dp} = await testRunner.startBlank(
'Tests compositor animated css handling.');
await dp.Target.enable();
// Open the test page in a new tab with BeginFrameControl enabled.
await testTargetPage(await testRunner.createTargetInNewContext(
session, 800, 600, 'about:blank', true));
// Loads a page with css animation into a a newly created tab with BeginFrame
// control and verifies that animation is advanced according to virtual time.
async function testTargetPage(session) {
dp = session.protocol;
await dp.Runtime.enable();
await dp.HeadlessExperimental.enable();
dp.Runtime.onConsoleAPICalled(data => {
const text = data.params.args[0].value;
testRunner.log(text);
});
let virtualTimeBase = 0;
let totalElapsedTime = 0;
let lastGrantedChunk = 0;
let expiredCount = 0;
dp.Emulation.onVirtualTimeBudgetExpired(async data => {
++expiredCount;
totalElapsedTime += lastGrantedChunk;
testRunner.log(`Expired count: ${expiredCount}`
+ `, elaspedTime: ${totalElapsedTime}`);
let grantVirtualTime = 500;
let frameTimeTicks = virtualTimeBase + totalElapsedTime;
if (expiredCount == 1) {
// Renderer wants the very first frame to be fully updated.
await dp.HeadlessExperimental.beginFrame({frameTimeTicks});
} else {
if (expiredCount >= 4 && expiredCount <= 6) {
// Issue updateless frames.
await dp.HeadlessExperimental.beginFrame(
{frameTimeTicks, noDisplayUpdates: true});
} else {
// Update frame and grab a screenshot, logging background color.
const {result: {screenshotData}} =
await dp.HeadlessExperimental.beginFrame(
{frameTimeTicks, screenshot: {format: 'png'}});
await logScreenShotInfo(screenshotData);
}
}
// Grant more time or quit test.
if (expiredCount < 10) {
await dp.Emulation.setVirtualTimePolicy({
policy: 'pauseIfNetworkFetchesPending',
budget: grantVirtualTime});
lastGrantedChunk = grantVirtualTime;
} else {
testRunner.completeTest();
}
});
// Pause for the first time and remember base virtual time.
const {result: {virtualTimeTicksBase}} =
await dp.Emulation.setVirtualTimePolicy({policy: 'pause'});
virtualTimeBase = virtualTimeTicksBase;
lastGrantedChunk = 500;
await dp.Emulation.setVirtualTimePolicy({
policy: 'pauseIfNetworkFetchesPending',
budget: lastGrantedChunk, waitForNavigation: true});
// Animates opacity of a blue 100px square on red blackground over 4
// seconds (1.0 -> 0 -> 1.0 four times). Logs events to console.
//
// Timeline:
// 0 ms: --- animation starts at 500ms ---
// 500 ms: 1.0 opacity -> blue background.
// 1000 ms: 0 opacity -> red background.
// 1500 ms: 1.0 opacity -> blue background.
// 2000 ms: 0 opacity -> red background.
// 2500 ms: 1.0 opacity -> blue background.
// 3000 ms: 0 opacity -> red background.
// 3500 ms: 1.0 opacity -> blue background.
// 4000 ms: 0 opacity -> red background.
// 4500 ms: 1.0 opacity -> blue background.
//
// The animation will start with the first BeginFrame after load.
dp.Page.navigate(
{url: testRunner.url('/resources/compositor-css-animation.html')});
function logScreenShotInfo(pngBase64) {
const image = new Image();
let callback;
let promise = new Promise(fulfill => callback = fulfill);
image.onload = function() {
const canvas = document.createElement('canvas');
canvas.width = image.naturalWidth;
canvas.height = image.naturalHeight;
const ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0);
const rgba = ctx.getImageData(0, 0, 1, 1).data;
testRunner.log(`Screenshot rgba: ${rgba}`);
callback();
}
image.src = `data:image/png;base64,${pngBase64}`;
return promise;
}
}
})
Tests compositor animated image handling.
Expired count: 1, elaspedTime: 500
Expired count: 2, elaspedTime: 1000
Expired count: 3, elaspedTime: 1500
Expired count: 4, elaspedTime: 2000
Expired count: 5, elaspedTime: 2500
Expired count: 6, elaspedTime: 3000
Expired count: 7, elaspedTime: 3500
Expired count: 8, elaspedTime: 4000
Screenshot rgba: 0,0,255,255
Expired count: 9, elaspedTime: 4500
Expired count: 10, elaspedTime: 5000
Expired count: 11, elaspedTime: 5500
Expired count: 12, elaspedTime: 6000
Expired count: 13, elaspedTime: 6500
Screenshot rgba: 255,255,0,255
Expired count: 14, elaspedTime: 7000
Expired count: 15, elaspedTime: 7500
Expired count: 16, elaspedTime: 8000
Expired count: 17, elaspedTime: 8500
Expired count: 18, elaspedTime: 9000
Expired count: 19, elaspedTime: 9500
Screenshot rgba: 255,255,0,255
Expired count: 20, elaspedTime: 10000
\ No newline at end of file
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
(async function(testRunner) {
var {page, session, dp} = await testRunner.startBlank(
'Tests compositor animated image handling.');
await dp.Target.enable();
// Open the test page in a new tab with BeginFrameControl enabled.
await testTargetPage(await testRunner.createTargetInNewContext(
session, 800, 600, 'about:blank', true));
// Loads an animated GIF into a a newly created tab with BeginFrame control
// and verifies that:
// - animate_only BeginFrames don't produce CompositorFrames,
// - first screenshot starts the GIF animation,
// - animation is advanced according to virtual time.
// - the animation is not resynced after the first iteration.
async function testTargetPage(session) {
dp = session.protocol;
await dp.Runtime.enable();
await dp.HeadlessExperimental.enable();
dp.Runtime.onConsoleAPICalled(data => {
const text = data.params.args[0].value;
testRunner.log(text);
});
let virtualTimeBase = 0;
let totalElapsedTime = 0;
let lastGrantedChunk = 0;
let expiredCount = 0;
dp.Emulation.onVirtualTimeBudgetExpired(async data => {
++expiredCount;
totalElapsedTime += lastGrantedChunk;
testRunner.log(`Expired count: ${expiredCount}, `
+ `elaspedTime: ${totalElapsedTime}`);
let grantVirtualTime = 500;
let frameTimeTicks = virtualTimeBase + totalElapsedTime;
if (expiredCount === 1 + 7
|| expiredCount === 1 + 7 + 5
|| expiredCount === 1 + 7 + 5 + 6) {
// Animation starts when first screenshot is taken, so the first
// screenshot should be blue. Screenshot #2 is taken on the third second
// of the animation, so it should be yellow. Screenshot #3 is taken two
// animation cycles later, so it should be yelloe again.
const {result: {screenshotData}} =
await dp.HeadlessExperimental.beginFrame(
{frameTimeTicks, screenshot: {format: 'png'}});
await logScreenShotInfo(screenshotData);
} else {
await dp.HeadlessExperimental.beginFrame(
{frameTimeTicks, noDisplayUpdates: true});
}
// Grant more time or quit test.
if (expiredCount < 20) {
await dp.Emulation.setVirtualTimePolicy({
policy: 'pauseIfNetworkFetchesPending',
budget: grantVirtualTime});
lastGrantedChunk = grantVirtualTime;
} else {
testRunner.completeTest();
}
});
// Pause for the first time and remember base virtual time.
const {result: {virtualTimeTicksBase}} =
await dp.Emulation.setVirtualTimePolicy(
{initialVirtualTime: 100, policy: 'pause'});
virtualTimeBase = virtualTimeTicksBase;
// Renderer wants the very first frame to be fully updated.
await dp.HeadlessExperimental.beginFrame({noDisplayUpdates: false});
// Grant initial time.
lastGrantedChunk = 500;
await dp.Emulation.setVirtualTimePolicy({
policy: 'pauseIfNetworkFetchesPending',
budget: lastGrantedChunk, waitForNavigation: true});
// The loaded GIF is 100x100px and has 1 second of blue, 1 second of red and
// 1 second of yellow.
dp.Page.navigate(
{url: testRunner.url('/resources/compositor-image-animation.html')});
async function AdvanceTime() {
await dp.Emulation.onceVirtualTimeBudgetExpired();
totalElapsedTime += lastGrantedChunk;
testRunner.log(`Elasped time: ${totalElapsedTime}`);
frameTimeTicks = virtualTimeBase + totalElapsedTime;
}
async function GrantMoreTime(budget) {
lastGrantedChunk = budget;
await dp.Emulation.setVirtualTimePolicy({
policy: 'pauseIfNetworkFetchesPending', budget});
}
function logScreenShotInfo(pngBase64) {
const image = new Image();
let callback;
let promise = new Promise(fulfill => callback = fulfill);
image.onload = function() {
const canvas = document.createElement('canvas');
canvas.width = image.naturalWidth;
canvas.height = image.naturalHeight;
const ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0);
const rgba = ctx.getImageData(0, 0, 1, 1).data;
testRunner.log(`Screenshot rgba: ${rgba}`);
callback();
}
image.src = `data:image/png;base64,${pngBase64}`;
return promise;
}
setTimeout(() => {
testRunner.log('Forced test termination');
testRunner.completeTest();
}, 10 * 1000);
}
})
<html>
<script>
window.rafCount = 0;
function animationCallback() {
++window.rafCount;
console.log(`Animation frame callback #${window.rafCount}`);
// Change document body background in a predictable manner.
document.body.style.background = '#0000' + (window.rafCount * 10).toString(16);
window.requestAnimationFrame(animationCallback);
}
function startRAF() {
console.log('Requesting first animation frame');
window.requestAnimationFrame(animationCallback);
}
function displayRAFCount() {
console.log(`Animation frame count: ${window.rafCount}`);
}
</script>
<body></body>
</html>
<!doctype html>
<style>
* {
margin: 0px;
background-color: red;
}
#box {
width: 100px;
height: 100px;
background-color: blue;
animation: flash 1s steps(1, end) 4;
}
@keyframes flash {
0% { opacity: 1; }
50% { opacity: 0; }
100% { opacity: 1; }
}
</style>
<div id="box"></div>
<script>
var baseTime = Date.now();
var box = document.getElementById("box");
box.addEventListener("animationstart", onAnimationEvent, false);
box.addEventListener("animationiteration", onAnimationEvent, false);
box.addEventListener("animationend", onAnimationEvent, false);
function onAnimationEvent(event) {
console.log(`Event [${event.type}]`
+ ` at ${event.elapsedTime} sec`);
}
</script>
<!doctype html>
<style>* { margin: 0; }</style>
<img id='image' src='animated_square.gif'>
......@@ -10,13 +10,8 @@
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/path_service.h"
#include "base/test/scoped_feature_list.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#include "cc/base/switches.h"
#include "components/viz/common/features.h"
#include "components/viz/common/switches.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test.h"
#include "headless/public/devtools/domains/runtime.h"
#include "headless/public/headless_browser.h"
......@@ -179,45 +174,10 @@ class HeadlessProtocolBrowserTest
builder.SetHostResolverRules("MAP *.test 127.0.0.1");
}
void SetUpCommandLine(base::CommandLine* command_line) override {
HeadlessAsyncDevTooledBrowserTest::SetUpCommandLine(command_line);
// The following switches are recommended for BeginFrameControl required by
// compositor tests, see https://goo.gl/3zHXhB for details
static const char* const compositor_switches[] = {
// We control BeginFrames ourselves and need all compositing stages to
// run.
switches::kRunAllCompositorStagesBeforeDraw,
switches::kDisableNewContentRenderingTimeout,
// Animtion-only BeginFrames are only supported when updates from the
// impl-thread are disabled, see go/headless-rendering.
cc::switches::kDisableThreadedAnimation,
cc::switches::kDisableCheckerImaging,
switches::kDisableThreadedScrolling,
// Ensure that image animations don't resync their animation timestamps
// when looping back around.
switches::kDisableImageAnimationResync,
};
for (auto* compositor_switch : compositor_switches) {
command_line->AppendSwitch(compositor_switch);
}
// In surface synchronization, child surface IDs are allocated by
// parents and new CompositorFrames only activate once all their child
// surfaces exist. In --run-all-compositor-stages-before-draw mode, this
// means that child surface initialization and resize fully propagates
// within a single BeginFrame.
scoped_feature_list_.InitAndEnableFeature(
features::kEnableSurfaceSynchronization);
}
protected:
bool test_finished_ = false;
std::string test_folder_;
std::string script_name_;
base::test::ScopedFeatureList scoped_feature_list_;
};
#define HEADLESS_PROTOCOL_TEST(TEST_NAME, SCRIPT_NAME) \
......@@ -262,28 +222,6 @@ HEADLESS_PROTOCOL_TEST(VirtualTimeVideo, "emulation/virtual-time-video.js");
HEADLESS_PROTOCOL_TEST(DISABLED_VirtualTimeHistoryNavigation,
"emulation/virtual-time-history-navigation.js");
// BeginFrameControl is not supported on MacOS yet, see: https://cs.chromium.org
// chromium/src/headless/lib/browser/protocol/target_handler.cc?
// rcl=5811aa08e60ba5ac7622f029163213cfbdb682f7&l=32
#if defined(OS_MACOSX)
#define MAYBE_CompositorBasicRaf DISABLED_CompositorBasicRaf
#define MAYBE_CompositorImageAnimation DISABLED_CompositorImageAnimation
#define MAYBE_CompositorCssAnimation DISABLED_CompositorCssAnimation
#else
#define MAYBE_CompositorBasicRaf CompositorBasicRaf
#define MAYBE_CompositorImageAnimation CompositorImageAnimation
#define MAYBE_CompositorCssAnimation CompositorCssAnimation
#endif
HEADLESS_PROTOCOL_TEST(MAYBE_CompositorBasicRaf,
"emulation/compositor-basic-raf.js");
HEADLESS_PROTOCOL_TEST(MAYBE_CompositorImageAnimation,
"emulation/compositor-image-animation-test.js");
HEADLESS_PROTOCOL_TEST(MAYBE_CompositorCssAnimation,
"emulation/compositor-css-animation-test.js");
#undef MAYBE_CompositorBasicRaf
#undef MAYBE_CompositorImageAnimation
#undef MAYBE_CompositorCssAnimation
// http://crbug.com/633321
#if defined(OS_ANDROID)
#define MAYBE_VirtualTimeTimerOrder DISABLED_VirtualTimeTimerOrder
......
......@@ -171,18 +171,6 @@ var TestRunner = class {
return this._start(description, null, url);
}
async createTargetInNewContext(session, width, height, url, enableBeginFrameControl) {
const dp = session.protocol;
const browserContextId = (await dp.Target.createBrowserContext())
.result.browserContextId;
const targetId = (await dp.Target.createTarget(
{url, browserContextId, width, height, enableBeginFrameControl}))
.result.targetId;
const sessionId = (await dp.Target.attachToTarget({targetId}))
.result.sessionId;
return session.createChild(sessionId);
}
async logStackTrace(debuggers, stackTrace, debuggerId) {
while (stackTrace) {
const {description, callFrames, parent, parentId} = stackTrace;
......
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