| 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 |