1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/command_line.h"
#include "base/containers/flat_map.h"
#include "base/functional/bind.h"
#include "base/run_loop.h"
#include "base/task/current_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_switches.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "content/renderer/render_frame_impl.h"
#include "content/shell/browser/shell.h"
#include "third_party/blink/public/web/web_view_observer.h"
namespace content {
class CommitObserver : public blink::WebViewObserver {
public:
explicit CommitObserver(blink::WebView* web_view)
: blink::WebViewObserver(web_view) {}
void DidCommitCompositorFrame() override {
commit_count_++;
for (const auto& pair : quit_closures_) {
pair.second.Run();
}
}
void QuitAfterCommit(int commit_number,
scoped_refptr<MessageLoopRunner> runner) {
if (commit_number >= commit_count_) runner->Quit();
}
void WaitForCommitNumber(int commit_number) {
if (commit_number > commit_count_) {
scoped_refptr<MessageLoopRunner> runner = new MessageLoopRunner;
quit_closures_[commit_number] =
base::BindRepeating(&CommitObserver::QuitAfterCommit,
base::Unretained(this), commit_number, runner);
runner->Run();
quit_closures_.erase(commit_number);
}
}
int GetCommitCount() { return commit_count_; }
private:
// blink::WebViewObserver implementation.
void OnDestruct() override { delete this; }
base::flat_map<int, base::RepeatingClosure> quit_closures_;
int commit_count_ = 0;
};
class VisualStateTest : public ContentBrowserTest {
public:
VisualStateTest() : callback_count_(0) {}
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(switches::kSingleProcess);
}
void WaitForCommit(CommitObserver *observer, int commit_number) {
observer->WaitForCommitNumber(commit_number);
EXPECT_EQ(commit_number, observer->GetCommitCount());
}
void AssertIsIdle() {
ASSERT_TRUE(base::CurrentThread::Get()->IsIdleForTesting());
}
void InvokeVisualStateCallback(bool result) {
EXPECT_TRUE(result);
callback_count_++;
}
int GetCallbackCount() { return callback_count_; }
private:
int callback_count_;
};
// This test verifies that visual state callbacks do not deadlock. In other
// words, the visual state callback should be received even if there are no
// pending updates or commits.
// Disabled due to cross-platform flakes; http://crbug.com/462580.
IN_PROC_BROWSER_TEST_F(VisualStateTest, DISABLED_CallbackDoesNotDeadlock) {
// This test relies on the fact that loading "about:blank" only requires a
// single commit. We first load "about:blank" and wait for this single
// commit. At that point we know that the page has stabilized and no
// further commits are expected. We then insert a visual state callback
// and verify that this causes an additional commit in order to deliver
// the callback.
// Unfortunately, if loading "about:blank" changes and starts requiring
// two commits then this test will prove nothing. We could detect this
// with a high level of confidence if we used a timeout, but that's
// discouraged (see https://codereview.chromium.org/939673002).
EXPECT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
CommitObserver observer(
blink::WebLocalFrame::FromFrameToken(
shell()->web_contents()->GetPrimaryMainFrame()->GetFrameToken())
->View());
// Wait for the commit corresponding to the load.
PostTaskToInProcessRendererAndWait(base::BindOnce(
&VisualStateTest::WaitForCommit, base::Unretained(this), &observer, 1));
// Try our best to check that there are no pending updates or commits.
PostTaskToInProcessRendererAndWait(
base::BindOnce(&VisualStateTest::AssertIsIdle, base::Unretained(this)));
// Insert a visual state callback.
shell()->web_contents()->GetPrimaryMainFrame()->InsertVisualStateCallback(
base::BindOnce(&VisualStateTest::InvokeVisualStateCallback,
base::Unretained(this)));
// Verify that the callback is invoked and a new commit completed.
PostTaskToInProcessRendererAndWait(base::BindOnce(
&VisualStateTest::WaitForCommit, base::Unretained(this), &observer, 2));
EXPECT_EQ(1, GetCallbackCount());
}
} // namespace content
|