1// Copyright (c) 2012 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/macros.h"
6#include "base/values.h"
7#include "chrome/browser/extensions/api/web_navigation/frame_navigation_state.h"
8#include "chrome/test/base/chrome_render_view_host_test_harness.h"
9#include "chrome/test/base/testing_profile.h"
10#include "testing/gtest/include/gtest/gtest.h"
11
12namespace extensions {
13
14class FrameNavigationStateTest : public ChromeRenderViewHostTestHarness {
15 protected:
16  FrameNavigationStateTest() {}
17  virtual ~FrameNavigationStateTest() {}
18
19  FrameNavigationState navigation_state_;
20
21 private:
22  DISALLOW_COPY_AND_ASSIGN(FrameNavigationStateTest);
23};
24
25// Test that a frame is correctly tracked, and removed once the tab contents
26// goes away.
27TEST_F(FrameNavigationStateTest, TrackFrame) {
28  const GURL url1("http://www.google.com/");
29  const GURL url2("http://mail.google.com/");
30
31  // Create a main frame.
32  EXPECT_FALSE(navigation_state_.CanSendEvents(main_rfh()));
33  EXPECT_FALSE(navigation_state_.IsValidFrame(main_rfh()));
34  navigation_state_.TrackFrame(main_rfh(), url1, false, false);
35  navigation_state_.SetNavigationCommitted(main_rfh());
36  EXPECT_TRUE(navigation_state_.CanSendEvents(main_rfh()));
37  EXPECT_TRUE(navigation_state_.IsValidFrame(main_rfh()));
38
39  // Add a sub frame.
40  content::RenderFrameHost* sub_frame =
41      content::RenderFrameHostTester::For(main_rfh())->AppendChild("child");
42  EXPECT_FALSE(navigation_state_.CanSendEvents(sub_frame));
43  EXPECT_FALSE(navigation_state_.IsValidFrame(sub_frame));
44  navigation_state_.TrackFrame(sub_frame, url2, false, false);
45  navigation_state_.SetNavigationCommitted(sub_frame);
46  EXPECT_TRUE(navigation_state_.CanSendEvents(sub_frame));
47  EXPECT_TRUE(navigation_state_.IsValidFrame(sub_frame));
48
49  // Check frame state.
50  EXPECT_EQ(url1, navigation_state_.GetUrl(main_rfh()));
51  EXPECT_EQ(url2, navigation_state_.GetUrl(sub_frame));
52  EXPECT_EQ(main_rfh(), navigation_state_.GetLastCommittedMainFrameHost());
53
54  // Drop the frames.
55  navigation_state_.StopTrackingFramesInRVH(rvh(), NULL);
56  EXPECT_FALSE(navigation_state_.CanSendEvents(main_rfh()));
57  EXPECT_FALSE(navigation_state_.IsValidFrame(main_rfh()));
58  EXPECT_FALSE(navigation_state_.CanSendEvents(sub_frame));
59  EXPECT_FALSE(navigation_state_.IsValidFrame(sub_frame));
60}
61
62// Test that no events can be sent for a frame after an error occurred, but
63// before a new navigation happened in this frame.
64TEST_F(FrameNavigationStateTest, ErrorState) {
65  const GURL url("http://www.google.com/");
66
67  navigation_state_.TrackFrame(main_rfh(), url, false, false);
68  EXPECT_TRUE(navigation_state_.CanSendEvents(main_rfh()));
69  EXPECT_FALSE(navigation_state_.GetErrorOccurredInFrame(main_rfh()));
70
71  // After an error occurred, no further events should be sent.
72  navigation_state_.SetErrorOccurredInFrame(main_rfh());
73  EXPECT_FALSE(navigation_state_.CanSendEvents(main_rfh()));
74  EXPECT_TRUE(navigation_state_.GetErrorOccurredInFrame(main_rfh()));
75
76  // Navigations to a network error page should be ignored.
77  navigation_state_.TrackFrame(main_rfh(), GURL(), true, false);
78  EXPECT_FALSE(navigation_state_.CanSendEvents(main_rfh()));
79  EXPECT_TRUE(navigation_state_.GetErrorOccurredInFrame(main_rfh()));
80
81  // However, when the frame navigates again, it should send events again.
82  navigation_state_.TrackFrame(main_rfh(), url, false, false);
83  EXPECT_TRUE(navigation_state_.CanSendEvents(main_rfh()));
84  EXPECT_FALSE(navigation_state_.GetErrorOccurredInFrame(main_rfh()));
85}
86
87// Tests that for a sub frame, no events are send after an error occurred, but
88// before a new navigation happened in this frame.
89TEST_F(FrameNavigationStateTest, ErrorStateFrame) {
90  const GURL url("http://www.google.com/");
91
92  content::RenderFrameHost* sub_frame =
93      content::RenderFrameHostTester::For(main_rfh())->AppendChild("child");
94  navigation_state_.TrackFrame(main_rfh(), url, false, false);
95  navigation_state_.TrackFrame(sub_frame, url, false, false);
96  EXPECT_TRUE(navigation_state_.CanSendEvents(main_rfh()));
97  EXPECT_TRUE(navigation_state_.CanSendEvents(sub_frame));
98
99  // After an error occurred, no further events should be sent.
100  navigation_state_.SetErrorOccurredInFrame(sub_frame);
101  EXPECT_TRUE(navigation_state_.CanSendEvents(main_rfh()));
102  EXPECT_FALSE(navigation_state_.CanSendEvents(sub_frame));
103
104  // Navigations to a network error page should be ignored.
105  navigation_state_.TrackFrame(sub_frame, GURL(), true, false);
106  EXPECT_TRUE(navigation_state_.CanSendEvents(main_rfh()));
107  EXPECT_FALSE(navigation_state_.CanSendEvents(sub_frame));
108
109  // However, when the frame navigates again, it should send events again.
110  navigation_state_.TrackFrame(sub_frame, url, false, false);
111  EXPECT_TRUE(navigation_state_.CanSendEvents(main_rfh()));
112  EXPECT_TRUE(navigation_state_.CanSendEvents(sub_frame));
113}
114
115// Tests that no events are send for a not web-safe scheme.
116TEST_F(FrameNavigationStateTest, WebSafeScheme) {
117  const GURL url("unsafe://www.google.com/");
118
119  navigation_state_.TrackFrame(main_rfh(), url, false, false);
120  EXPECT_FALSE(navigation_state_.CanSendEvents(main_rfh()));
121}
122
123// Test for <iframe srcdoc=""> frames.
124TEST_F(FrameNavigationStateTest, SrcDoc) {
125  const GURL url("http://www.google.com/");
126  const GURL blank("about:blank");
127  const GURL srcdoc("about:srcdoc");
128
129  content::RenderFrameHost* sub_frame =
130      content::RenderFrameHostTester::For(main_rfh())->AppendChild("child");
131  navigation_state_.TrackFrame(main_rfh(), url, false, false);
132  navigation_state_.TrackFrame(sub_frame, blank, false, true);
133  EXPECT_TRUE(navigation_state_.CanSendEvents(main_rfh()));
134  EXPECT_TRUE(navigation_state_.CanSendEvents(sub_frame));
135
136  EXPECT_EQ(url, navigation_state_.GetUrl(main_rfh()));
137  EXPECT_EQ(srcdoc, navigation_state_.GetUrl(sub_frame));
138
139  EXPECT_TRUE(navigation_state_.IsValidUrl(srcdoc));
140}
141
142// Test that an individual frame can be detached.
143TEST_F(FrameNavigationStateTest, DetachFrame) {
144  const GURL url1("http://www.google.com/");
145  const GURL url2("http://mail.google.com/");
146
147  // Create a main frame.
148  EXPECT_FALSE(navigation_state_.CanSendEvents(main_rfh()));
149  EXPECT_FALSE(navigation_state_.IsValidFrame(main_rfh()));
150  navigation_state_.TrackFrame(main_rfh(), url1, false, false);
151  navigation_state_.SetNavigationCommitted(main_rfh());
152  EXPECT_TRUE(navigation_state_.CanSendEvents(main_rfh()));
153  EXPECT_TRUE(navigation_state_.IsValidFrame(main_rfh()));
154
155  // Add a sub frame.
156  content::RenderFrameHost* sub_frame =
157      content::RenderFrameHostTester::For(main_rfh())->AppendChild("child");
158  EXPECT_FALSE(navigation_state_.CanSendEvents(sub_frame));
159  EXPECT_FALSE(navigation_state_.IsValidFrame(sub_frame));
160  navigation_state_.TrackFrame(sub_frame, url2, false, false);
161  navigation_state_.SetNavigationCommitted(sub_frame);
162  EXPECT_TRUE(navigation_state_.CanSendEvents(sub_frame));
163  EXPECT_TRUE(navigation_state_.IsValidFrame(sub_frame));
164
165  // Check frame state.
166  EXPECT_EQ(url1, navigation_state_.GetUrl(main_rfh()));
167  EXPECT_EQ(url2, navigation_state_.GetUrl(sub_frame));
168  EXPECT_EQ(main_rfh(), navigation_state_.GetLastCommittedMainFrameHost());
169
170  // Drop one frame.
171  navigation_state_.FrameDetached(sub_frame);
172  EXPECT_EQ(url1, navigation_state_.GetUrl(main_rfh()));
173  EXPECT_EQ(main_rfh(), navigation_state_.GetLastCommittedMainFrameHost());
174  EXPECT_FALSE(navigation_state_.CanSendEvents(sub_frame));
175  EXPECT_FALSE(navigation_state_.IsValidFrame(sub_frame));
176}
177
178}  // namespace extensions
179