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
content / renderer / visual_state_browsertest.cc [blame]
// 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