OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import <Foundation/Foundation.h> | 5 #import <Foundation/Foundation.h> |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "base/files/file_path.h" | 9 #include "base/files/file_path.h" |
10 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
11 #include "base/files/scoped_temp_dir.h" | 11 #include "base/files/scoped_temp_dir.h" |
12 #include "base/path_service.h" | 12 #include "base/path_service.h" |
| 13 #include "base/run_loop.h" |
13 #include "base/strings/sys_string_conversions.h" | 14 #include "base/strings/sys_string_conversions.h" |
14 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" | 15 #include "base/test/scoped_task_environment.h" |
| 16 #include "base/threading/thread_task_runner_handle.h" |
15 #include "ios/chrome/browser/chrome_paths.h" | 17 #include "ios/chrome/browser/chrome_paths.h" |
16 #import "ios/chrome/browser/sessions/session_service_ios.h" | 18 #import "ios/chrome/browser/sessions/session_service_ios.h" |
17 #import "ios/chrome/browser/sessions/session_window_ios.h" | 19 #import "ios/chrome/browser/sessions/session_window_ios.h" |
18 #include "ios/web/public/navigation_item.h" | 20 #import "ios/web/public/crw_session_storage.h" |
19 #import "ios/web/public/navigation_manager.h" | |
20 #include "ios/web/public/test/test_web_thread_bundle.h" | |
21 #include "testing/gtest/include/gtest/gtest.h" | 21 #include "testing/gtest/include/gtest/gtest.h" |
22 #include "testing/gtest_mac.h" | 22 #include "testing/gtest_mac.h" |
23 #include "testing/platform_test.h" | 23 #include "testing/platform_test.h" |
24 #import "third_party/ocmock/OCMock/OCMock.h" | |
25 | 24 |
26 #if !defined(__has_feature) || !__has_feature(objc_arc) | 25 #if !defined(__has_feature) || !__has_feature(objc_arc) |
27 #error "This file requires ARC support." | 26 #error "This file requires ARC support." |
28 #endif | 27 #endif |
29 | 28 |
30 namespace { | 29 namespace { |
31 | 30 |
32 // Fixture Class. Takes care of deleting the directory used to store test data. | 31 // Fixture Class. Takes care of deleting the directory used to store test data. |
33 class SessionServiceTest : public PlatformTest { | 32 class SessionServiceTest : public PlatformTest { |
34 public: | 33 public: |
35 SessionServiceTest() = default; | 34 SessionServiceTest() = default; |
36 ~SessionServiceTest() override = default; | 35 ~SessionServiceTest() override = default; |
37 | 36 |
38 protected: | 37 protected: |
39 void SetUp() override { | 38 void SetUp() override { |
40 PlatformTest::SetUp(); | 39 PlatformTest::SetUp(); |
41 ASSERT_TRUE(test_dir_.CreateUniqueTempDir()); | 40 ASSERT_TRUE(scoped_temp_directory_.CreateUniqueTempDir()); |
42 TestChromeBrowserState::Builder test_cbs_builder; | 41 base::FilePath directory_name = scoped_temp_directory_.GetPath(); |
43 test_cbs_builder.SetPath(test_dir_.GetPath()); | 42 directory_name = directory_name.Append(FILE_PATH_LITERAL("sessions")); |
44 chrome_browser_state_ = test_cbs_builder.Build(); | 43 directory_ = base::SysUTF8ToNSString(directory_name.AsUTF8Unsafe()); |
45 directory_name_ = [base::SysUTF8ToNSString( | 44 |
46 chrome_browser_state_->GetStatePath().value()) copy]; | 45 scoped_refptr<base::SequencedTaskRunner> task_runner = |
| 46 base::ThreadTaskRunnerHandle::Get(); |
| 47 session_service_ = |
| 48 [[SessionServiceIOS alloc] initWithTaskRunner:task_runner]; |
47 } | 49 } |
48 | 50 |
49 // Helper function to load a SessionWindowIOS from a given testdata | 51 void TearDown() override { |
50 // |filename|. Returns nil if there was an error loading the session. | 52 session_service_ = nil; |
51 SessionWindowIOS* LoadSessionFromTestDataFile( | 53 PlatformTest::TearDown(); |
52 const base::FilePath::StringType& filename) { | |
53 SessionServiceIOS* service = [SessionServiceIOS sharedService]; | |
54 base::FilePath plist_path; | |
55 bool success = PathService::Get(ios::DIR_TEST_DATA, &plist_path); | |
56 EXPECT_TRUE(success); | |
57 if (!success) { | |
58 return nil; | |
59 } | |
60 | |
61 plist_path = plist_path.AppendASCII("sessions"); | |
62 plist_path = plist_path.Append(filename); | |
63 EXPECT_TRUE(base::PathExists(plist_path)); | |
64 | |
65 NSString* path = base::SysUTF8ToNSString(plist_path.value()); | |
66 return [service loadWindowFromPath:path]; | |
67 } | 54 } |
68 | 55 |
69 ios::ChromeBrowserState* chrome_browser_state() { | 56 // Returns the path to serialized SessionWindowIOS from a testdata file named |
70 return chrome_browser_state_.get(); | 57 // |filename| or nil if the file cannot be found. |
| 58 NSString* SessionPathForTestData(const base::FilePath::CharType* filename) { |
| 59 base::FilePath session_path; |
| 60 if (!PathService::Get(ios::DIR_TEST_DATA, &session_path)) |
| 61 return nil; |
| 62 |
| 63 session_path = session_path.Append(FILE_PATH_LITERAL("sessions")); |
| 64 session_path = session_path.Append(filename); |
| 65 if (!base::PathExists(session_path)) |
| 66 return nil; |
| 67 |
| 68 return base::SysUTF8ToNSString(session_path.AsUTF8Unsafe()); |
71 } | 69 } |
72 | 70 |
73 NSString* directory_name() { return directory_name_; } | 71 // Create a SessionWindowIOS with |tab_count| tabs. |
| 72 SessionWindowIOS* CreateSessionWindow(NSUInteger tab_count) { |
| 73 NSMutableArray<CRWSessionStorage*>* tabs = [NSMutableArray array]; |
| 74 while (tabs.count < tab_count) { |
| 75 [tabs addObject:[[CRWSessionStorage alloc] init]]; |
| 76 } |
| 77 return [[SessionWindowIOS alloc] |
| 78 initWithSessions:[tabs copy] |
| 79 selectedIndex:(tabs.count ? tabs.count - 1 : NSNotFound)]; |
| 80 } |
| 81 |
| 82 SessionServiceIOS* session_service() { return session_service_; } |
| 83 |
| 84 NSString* directory() { return directory_; } |
74 | 85 |
75 private: | 86 private: |
76 base::ScopedTempDir test_dir_; | 87 base::ScopedTempDir scoped_temp_directory_; |
77 web::TestWebThreadBundle thread_bundle_; | 88 base::test::ScopedTaskEnvironment scoped_task_environment_; |
78 std::unique_ptr<ios::ChromeBrowserState> chrome_browser_state_; | 89 SessionServiceIOS* session_service_; |
79 NSString* directory_name_; | 90 NSString* directory_; |
80 | 91 |
81 DISALLOW_COPY_AND_ASSIGN(SessionServiceTest); | 92 DISALLOW_COPY_AND_ASSIGN(SessionServiceTest); |
82 }; | 93 }; |
83 | 94 |
84 TEST_F(SessionServiceTest, Singleton) { | 95 TEST_F(SessionServiceTest, SessionPathForDirectory) { |
85 SessionServiceIOS* service = [SessionServiceIOS sharedService]; | 96 EXPECT_NSEQ(@"session.plist", |
86 EXPECT_TRUE(service != nil); | 97 [SessionServiceIOS sessionPathForDirectory:@""]); |
87 | |
88 SessionServiceIOS* another_service = [SessionServiceIOS sharedService]; | |
89 EXPECT_TRUE(another_service != nil); | |
90 | |
91 EXPECT_TRUE(service == another_service); | |
92 } | 98 } |
93 | 99 |
94 TEST_F(SessionServiceTest, SaveWindowToDirectory) { | 100 TEST_F(SessionServiceTest, SaveSessionWindowToDirectory) { |
95 id session_window_mock = | 101 [session_service() saveSessionWindow:CreateSessionWindow(0u) |
96 [OCMockObject niceMockForClass:[SessionWindowIOS class]]; | 102 directory:directory() |
97 SessionServiceIOS* service = [SessionServiceIOS sharedService]; | 103 immediately:YES]; |
98 [service performSaveWindow:session_window_mock toDirectory:directory_name()]; | 104 |
| 105 // Even if immediately is YES, the file is created by a task on the task |
| 106 // runner passed to SessionServiceIOS initializer (which is the current |
| 107 // thread task runner during test). Wait for the task to complete. |
| 108 base::RunLoop().RunUntilIdle(); |
99 | 109 |
100 NSFileManager* file_manager = [NSFileManager defaultManager]; | 110 NSFileManager* file_manager = [NSFileManager defaultManager]; |
101 EXPECT_TRUE([file_manager removeItemAtPath:directory_name() error:nullptr]); | 111 EXPECT_TRUE([file_manager removeItemAtPath:directory() error:nullptr]); |
102 } | 112 } |
103 | 113 |
104 TEST_F(SessionServiceTest, SaveWindowToDirectoryAlreadyExistent) { | 114 TEST_F(SessionServiceTest, SaveSessionWindowToExistingDirectory) { |
105 id session_window_mock = | 115 ASSERT_TRUE([[NSFileManager defaultManager] createDirectoryAtPath:directory() |
106 [OCMockObject niceMockForClass:[SessionWindowIOS class]]; | 116 withIntermediateDirectories:YES |
107 EXPECT_TRUE([[NSFileManager defaultManager] | 117 attributes:nil |
108 createDirectoryAtPath:directory_name() | 118 error:nullptr]); |
109 withIntermediateDirectories:YES | |
110 attributes:nil | |
111 error:nullptr]); | |
112 | 119 |
113 SessionServiceIOS* service = [SessionServiceIOS sharedService]; | 120 [session_service() saveSessionWindow:CreateSessionWindow(0u) |
114 [service performSaveWindow:session_window_mock toDirectory:directory_name()]; | 121 directory:directory() |
| 122 immediately:YES]; |
| 123 |
| 124 // Even if immediately is YES, the file is created by a task on the task |
| 125 // runner passed to SessionServiceIOS initializer (which is the current |
| 126 // thread task runner during test). Wait for the task to complete. |
| 127 base::RunLoop().RunUntilIdle(); |
115 | 128 |
116 NSFileManager* file_manager = [NSFileManager defaultManager]; | 129 NSFileManager* file_manager = [NSFileManager defaultManager]; |
117 EXPECT_TRUE([file_manager removeItemAtPath:directory_name() error:nullptr]); | 130 EXPECT_TRUE([file_manager removeItemAtPath:directory() error:nullptr]); |
118 } | 131 } |
119 | 132 |
120 TEST_F(SessionServiceTest, LoadEmptyWindowFromDirectory) { | 133 TEST_F(SessionServiceTest, LoadSessionWindowFromDirectoryNoFile) { |
121 SessionServiceIOS* service = [SessionServiceIOS sharedService]; | |
122 SessionWindowIOS* session_window = | 134 SessionWindowIOS* session_window = |
123 [service loadWindowForBrowserState:chrome_browser_state()]; | 135 [session_service() loadSessionWindowFromDirectory:directory()]; |
124 EXPECT_TRUE(session_window == nil); | 136 EXPECT_TRUE(session_window == nil); |
125 } | 137 } |
126 | 138 |
127 TEST_F(SessionServiceTest, LoadWindowFromDirectory) { | 139 TEST_F(SessionServiceTest, LoadSessionWindowFromDirectory) { |
128 SessionServiceIOS* service = [SessionServiceIOS sharedService]; | 140 [session_service() saveSessionWindow:CreateSessionWindow(1u) |
129 SessionWindowIOS* origSessionWindow = [[SessionWindowIOS alloc] init]; | 141 directory:directory() |
130 [service performSaveWindow:origSessionWindow toDirectory:directory_name()]; | 142 immediately:YES]; |
| 143 |
| 144 // Even if immediately is YES, the file is created by a task on the task |
| 145 // runner passed to SessionServiceIOS initializer (which is the current |
| 146 // thread task runner during test). Wait for the task to complete. |
| 147 base::RunLoop().RunUntilIdle(); |
131 | 148 |
132 SessionWindowIOS* session_window = | 149 SessionWindowIOS* session_window = |
133 [service loadWindowForBrowserState:chrome_browser_state()]; | 150 [session_service() loadSessionWindowFromDirectory:directory()]; |
134 EXPECT_TRUE(session_window != nil); | 151 EXPECT_EQ(1u, session_window.sessions.count); |
135 EXPECT_EQ(NSNotFound, static_cast<NSInteger>(session_window.selectedIndex)); | 152 EXPECT_EQ(0u, session_window.selectedIndex); |
136 EXPECT_EQ(0U, session_window.sessions.count); | |
137 } | 153 } |
138 | 154 |
139 TEST_F(SessionServiceTest, LoadCorruptedWindow) { | 155 TEST_F(SessionServiceTest, LoadSessionWindowFromPath) { |
| 156 [session_service() saveSessionWindow:CreateSessionWindow(1u) |
| 157 directory:directory() |
| 158 immediately:YES]; |
| 159 |
| 160 // Even if immediately is YES, the file is created by a task on the task |
| 161 // runner passed to SessionServiceIOS initializer (which is the current |
| 162 // thread task runner during test). Wait for the task to complete. |
| 163 base::RunLoop().RunUntilIdle(); |
| 164 |
| 165 NSString* session_path = |
| 166 [SessionServiceIOS sessionPathForDirectory:directory()]; |
| 167 NSString* renamed_path = [session_path stringByAppendingPathExtension:@"bak"]; |
| 168 ASSERT_NSNE(session_path, renamed_path); |
| 169 |
| 170 // Rename the file. |
| 171 ASSERT_TRUE([[NSFileManager defaultManager] moveItemAtPath:session_path |
| 172 toPath:renamed_path |
| 173 error:nil]); |
| 174 |
140 SessionWindowIOS* session_window = | 175 SessionWindowIOS* session_window = |
141 LoadSessionFromTestDataFile(FILE_PATH_LITERAL("corrupted.plist")); | 176 [session_service() loadSessionWindowFromPath:renamed_path]; |
| 177 EXPECT_EQ(1u, session_window.sessions.count); |
| 178 EXPECT_EQ(0u, session_window.selectedIndex); |
| 179 } |
| 180 |
| 181 TEST_F(SessionServiceTest, LoadCorruptedSessionWindow) { |
| 182 NSString* session_path = |
| 183 SessionPathForTestData(FILE_PATH_LITERAL("corrupted.plist")); |
| 184 ASSERT_NSNE(nil, session_path); |
| 185 SessionWindowIOS* session_window = |
| 186 [session_service() loadSessionWindowFromPath:session_path]; |
142 EXPECT_TRUE(session_window == nil); | 187 EXPECT_TRUE(session_window == nil); |
143 } | 188 } |
144 | 189 |
145 // TODO(crbug.com/661633): remove this once M67 has shipped (i.e. once more | 190 // TODO(crbug.com/661633): remove this once M67 has shipped (i.e. once more |
146 // than a year has passed since the introduction of the compatibility code). | 191 // than a year has passed since the introduction of the compatibility code). |
147 TEST_F(SessionServiceTest, LoadM57Session) { | 192 TEST_F(SessionServiceTest, LoadM57Session) { |
| 193 NSString* session_path = |
| 194 SessionPathForTestData(FILE_PATH_LITERAL("session_m57.plist")); |
| 195 ASSERT_NSNE(nil, session_path); |
148 SessionWindowIOS* session_window = | 196 SessionWindowIOS* session_window = |
149 LoadSessionFromTestDataFile(FILE_PATH_LITERAL("session_m57.plist")); | 197 [session_service() loadSessionWindowFromPath:session_path]; |
150 EXPECT_TRUE(session_window != nil); | 198 EXPECT_TRUE(session_window != nil); |
151 } | 199 } |
152 | 200 |
153 // TODO(crbug.com/661633): remove this once M68 has shipped (i.e. once more | 201 // TODO(crbug.com/661633): remove this once M68 has shipped (i.e. once more |
154 // than a year has passed since the introduction of the compatibility code). | 202 // than a year has passed since the introduction of the compatibility code). |
155 TEST_F(SessionServiceTest, LoadM58Session) { | 203 TEST_F(SessionServiceTest, LoadM58Session) { |
| 204 NSString* session_path = |
| 205 SessionPathForTestData(FILE_PATH_LITERAL("session_m58.plist")); |
| 206 ASSERT_NSNE(nil, session_path); |
156 SessionWindowIOS* session_window = | 207 SessionWindowIOS* session_window = |
157 LoadSessionFromTestDataFile(FILE_PATH_LITERAL("session_m58.plist")); | 208 [session_service() loadSessionWindowFromPath:session_path]; |
158 EXPECT_TRUE(session_window != nil); | 209 EXPECT_TRUE(session_window != nil); |
159 } | 210 } |
160 | 211 |
161 } // anonymous namespace | 212 } // anonymous namespace |
OLD | NEW |