OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "base/bind.h" | |
6 #include "base/run_loop.h" | |
7 #include "content/public/test/test_browser_thread_bundle.h" | |
8 #include "extensions/browser/extension_api_frame_id_map.h" | |
9 #include "testing/gtest/include/gtest/gtest.h" | |
10 | |
11 using FrameIdCallback = extensions::ExtensionApiFrameIdMap::FrameIdCallback; | |
12 | |
13 namespace extensions { | |
14 | |
15 namespace { | |
16 | |
17 int ToTestFrameId(int render_process_id, int frame_routing_id) { | |
18 if (render_process_id == -1 && frame_routing_id == -1) | |
19 return ExtensionApiFrameIdMap::kInvalidFrameId; | |
20 // Return a deterministic value (yet different from the input) for testing. | |
21 // To make debugging easier: Ending with 0 = frame ID. | |
22 return render_process_id * 1000 + frame_routing_id * 10; | |
23 } | |
24 | |
25 int ToTestParentFrameId(int render_process_id, int frame_routing_id) { | |
26 if (render_process_id == -1 && frame_routing_id == -1) | |
27 return ExtensionApiFrameIdMap::kInvalidFrameId; | |
28 // Return a deterministic value (yet different from the input) for testing. | |
29 // To make debugging easier: Ending with 7 = parent frame ID. | |
30 return render_process_id * 1000 + frame_routing_id * 10 + 7; | |
31 } | |
32 | |
33 class TestExtensionApiFrameIdMap : public ExtensionApiFrameIdMap { | |
34 public: | |
35 int GetInternalSize() { return frame_id_map_.size(); } | |
36 int GetInternalCallbackCount() { | |
37 int count = 0; | |
38 for (auto& it : callbacks_map_) | |
39 count += it.second.callbacks.size(); | |
40 return count; | |
41 } | |
42 | |
43 // These indirections are necessary because we cannot mock RenderFrameHost | |
44 // in unit tests :( | |
nasko
2016/01/05 00:39:58
You technically can. Using TestRenderFrameHost and
robwu
2016/01/05 10:59:03
Those are not in the public part of content/, incl
nasko
2016/01/06 17:19:38
The harness is public: content/public/test/test_re
robwu
2016/01/06 17:48:59
Thanks for this pointer, that could work indeed. I
| |
45 void SetInternalFrameId(int render_process_id, int frame_routing_id) { | |
46 CacheFrameId(RenderFrameIdKey(render_process_id, frame_routing_id)); | |
47 } | |
48 void RemoveInternalFrameId(int render_process_id, int frame_routing_id) { | |
49 RemoveFrameId(RenderFrameIdKey(render_process_id, frame_routing_id)); | |
50 } | |
51 | |
52 private: | |
53 // ExtensionApiFrameIdMap: | |
54 CachedFrameIdPair KeyToValue(const RenderFrameIdKey& key) const override { | |
55 return CachedFrameIdPair( | |
56 ToTestFrameId(key.render_process_id, key.frame_routing_id), | |
57 ToTestParentFrameId(key.render_process_id, key.frame_routing_id)); | |
58 } | |
59 }; | |
60 | |
61 class ExtensionApiFrameIdMapTest : public testing::Test { | |
62 public: | |
63 ExtensionApiFrameIdMapTest() | |
64 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {} | |
65 | |
66 FrameIdCallback CreateCallback(int render_process_id, | |
67 int frame_routing_id, | |
68 const std::string& callback_name_for_testing) { | |
69 return base::Bind(&ExtensionApiFrameIdMapTest::OnCalledCallback, | |
70 base::Unretained(this), render_process_id, | |
71 frame_routing_id, callback_name_for_testing); | |
72 } | |
73 | |
74 void OnCalledCallback(int render_process_id, | |
75 int frame_routing_id, | |
76 const std::string& callback_name_for_testing, | |
77 int extension_api_frame_id, | |
78 int extension_api_parent_frame_id) { | |
79 results_.push_back(callback_name_for_testing); | |
80 | |
81 // If this fails, then the mapping is completely wrong. | |
82 EXPECT_EQ(ToTestFrameId(render_process_id, frame_routing_id), | |
83 extension_api_frame_id); | |
84 EXPECT_EQ(ToTestParentFrameId(render_process_id, frame_routing_id), | |
85 extension_api_parent_frame_id); | |
86 } | |
87 | |
88 const std::vector<std::string>& results() { return results_; } | |
89 void ClearResults() { results_.clear(); } | |
90 | |
91 private: | |
92 content::TestBrowserThreadBundle thread_bundle_; | |
93 // Used to verify the order of callbacks. | |
94 std::vector<std::string> results_; | |
95 | |
96 DISALLOW_COPY_AND_ASSIGN(ExtensionApiFrameIdMapTest); | |
97 }; | |
98 | |
99 } // namespace | |
100 | |
101 TEST_F(ExtensionApiFrameIdMapTest, GetFrameIdOnIO) { | |
102 TestExtensionApiFrameIdMap map; | |
103 EXPECT_EQ(0, map.GetInternalSize()); | |
104 | |
105 // Two identical calls, should be processed at the next message loop. | |
106 map.GetFrameIdOnIO(1, 2, CreateCallback(1, 2, "first")); | |
107 EXPECT_EQ(1, map.GetInternalCallbackCount()); | |
108 EXPECT_EQ(0, map.GetInternalSize()); | |
109 | |
110 map.GetFrameIdOnIO(1, 2, CreateCallback(1, 2, "first again")); | |
111 EXPECT_EQ(2, map.GetInternalCallbackCount()); | |
112 EXPECT_EQ(0, map.GetInternalSize()); | |
113 | |
114 // First get the frame ID on IO (queued on message loop), then set it on UI. | |
115 // No callbacks should be invoked because the IO thread cannot know that the | |
116 // frame ID was set on the UI thread. | |
117 map.GetFrameIdOnIO(2, 1, CreateCallback(2, 1, "something else")); | |
118 EXPECT_EQ(3, map.GetInternalCallbackCount()); | |
119 EXPECT_EQ(0, map.GetInternalSize()); | |
120 | |
121 map.SetInternalFrameId(2, 1); | |
122 EXPECT_EQ(1, map.GetInternalSize()); | |
123 EXPECT_EQ(0U, results().size()); | |
124 | |
125 // Run some self-contained test. They should not affect the above callbacks. | |
126 { | |
127 // First set the frame ID on UI, then get it on IO. Callback should | |
128 // immediately be invoked. | |
129 map.SetInternalFrameId(3, 1); | |
130 EXPECT_EQ(2, map.GetInternalSize()); | |
131 | |
132 map.GetFrameIdOnIO(3, 1, CreateCallback(3, 1, "the only result")); | |
133 EXPECT_EQ(3, map.GetInternalCallbackCount()); // No change. | |
134 EXPECT_EQ(2, map.GetInternalSize()); // +1 | |
135 ASSERT_EQ(1U, results().size()); // +1 | |
136 EXPECT_EQ("the only result", results()[0]); | |
137 ClearResults(); | |
138 } | |
139 | |
140 { | |
141 // Request the frame ID on IO, set the frame ID (in reality, set on the UI), | |
142 // and request another frame ID. The last query should cause both callbacks | |
143 // to run because the frame ID is known at the time of the call. | |
144 map.GetFrameIdOnIO(7, 2, CreateCallback(7, 2, "queued")); | |
145 EXPECT_EQ(4, map.GetInternalCallbackCount()); // +1 | |
146 | |
147 map.SetInternalFrameId(7, 2); | |
148 EXPECT_EQ(3, map.GetInternalSize()); // +1 | |
149 | |
150 map.GetFrameIdOnIO(7, 2, CreateCallback(7, 2, "not queued")); | |
151 EXPECT_EQ(3, map.GetInternalCallbackCount()); // -1 (first callback ran). | |
152 EXPECT_EQ(3, map.GetInternalSize()); // No change. | |
153 ASSERT_EQ(2U, results().size()); // +2 (both callbacks ran). | |
154 EXPECT_EQ("queued", results()[0]); | |
155 EXPECT_EQ("not queued", results()[1]); | |
156 ClearResults(); | |
157 } | |
158 | |
159 // A call identical to the very first call. | |
160 map.GetFrameIdOnIO(1, 2, CreateCallback(1, 2, "same as first")); | |
161 EXPECT_EQ(4, map.GetInternalCallbackCount()); | |
162 EXPECT_EQ(3, map.GetInternalSize()); | |
163 | |
164 // Trigger the queued callbacks. | |
165 base::RunLoop().RunUntilIdle(); | |
166 EXPECT_EQ(0, map.GetInternalCallbackCount()); // -4 (no queued callbacks). | |
167 | |
168 EXPECT_EQ(4, map.GetInternalSize()); // +1 (1 new cached frame ID). | |
169 ASSERT_EQ(4U, results().size()); // +4 (callbacks ran). | |
170 | |
171 // PostTasks are processed in order, so the very first callbacks should be | |
172 // processed. As soon as the first callback is available, all of its callbacks | |
173 // should be run (no deferrals!). | |
174 EXPECT_EQ("first", results()[0]); | |
175 EXPECT_EQ("first again", results()[1]); | |
176 EXPECT_EQ("same as first", results()[2]); | |
177 // This was queued after "first again", but has a different frame ID, so it | |
178 // is received after "same as first". | |
179 EXPECT_EQ("something else", results()[3]); | |
180 ClearResults(); | |
181 | |
182 // Request the frame ID for input that was already looked up. Should complete | |
183 // synchronously. | |
184 map.GetFrameIdOnIO(1, 2, CreateCallback(1, 2, "first and cached")); | |
185 EXPECT_EQ(0, map.GetInternalCallbackCount()); // No change. | |
186 EXPECT_EQ(4, map.GetInternalSize()); // No change. | |
187 ASSERT_EQ(1U, results().size()); // +1 (synchronous callback). | |
188 EXPECT_EQ("first and cached", results()[0]); | |
189 ClearResults(); | |
190 | |
191 // Trigger frame removal and look up frame ID. The frame ID should no longer | |
192 // be available. and GetFrameIdOnIO() should require a thread hop. | |
193 map.RemoveInternalFrameId(1, 2); | |
194 EXPECT_EQ(3, map.GetInternalSize()); // -1 | |
195 map.GetFrameIdOnIO(1, 2, CreateCallback(1, 2, "first was removed")); | |
196 EXPECT_EQ(1, map.GetInternalCallbackCount()); // +1 | |
197 ASSERT_EQ(0U, results().size()); // No change (queued callback). | |
198 base::RunLoop().RunUntilIdle(); | |
199 EXPECT_EQ(0, map.GetInternalCallbackCount()); // -1 (callback not in queue). | |
200 EXPECT_EQ(4, map.GetInternalSize()); // +1 (cached frame ID). | |
201 ASSERT_EQ(1U, results().size()); // +1 (callback ran). | |
202 EXPECT_EQ("first was removed", results()[0]); | |
203 } | |
204 | |
205 } // namespace extensions | |
OLD | NEW |