[go: nahoru, domu]

blob: 58a497fb03cf362fdb1761c72c9185ab846b2467 [file] [log] [blame]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.h"
#import <UIKit/UIKit.h>
#import <memory>
#import "base/apple/foundation_util.h"
#import "base/functional/bind.h"
#import "base/test/ios/wait_util.h"
#import "components/sessions/core/serialized_navigation_entry_test_helper.h"
#import "components/signin/public/identity_manager/identity_manager.h"
#import "components/signin/public/identity_manager/identity_test_environment.h"
#import "components/signin/public/identity_manager/primary_account_mutator.h"
#import "components/sync/base/user_selectable_type.h"
#import "components/sync/service/sync_service.h"
#import "components/sync/test/fake_model_type_controller_delegate.h"
#import "components/sync/test/test_sync_service.h"
#import "components/sync_sessions/open_tabs_ui_delegate.h"
#import "components/sync_sessions/session_sync_service.h"
#import "components/sync_sessions/synced_session.h"
#import "components/sync_user_events/global_id_mapper.h"
#import "ios/chrome/browser/favicon/favicon_service_factory.h"
#import "ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.h"
#import "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h"
#import "ios/chrome/browser/history/history_service_factory.h"
#import "ios/chrome/browser/sessions/ios_chrome_tab_restore_service_factory.h"
#import "ios/chrome/browser/shared/model/application_context/application_context.h"
#import "ios/chrome/browser/shared/model/browser/test/test_browser.h"
#import "ios/chrome/browser/shared/model/browser_state/test_chrome_browser_state.h"
#import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
#import "ios/chrome/browser/shared/public/commands/application_commands.h"
#import "ios/chrome/browser/shared/public/commands/browsing_data_commands.h"
#import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
#import "ios/chrome/browser/signin/authentication_service.h"
#import "ios/chrome/browser/signin/authentication_service_factory.h"
#import "ios/chrome/browser/signin/fake_authentication_service_delegate.h"
#import "ios/chrome/browser/signin/fake_system_identity.h"
#import "ios/chrome/browser/signin/fake_system_identity_manager.h"
#import "ios/chrome/browser/sync/session_sync_service_factory.h"
#import "ios/chrome/browser/sync/sync_service_factory.h"
#import "ios/chrome/browser/sync/sync_setup_service.h"
#import "ios/chrome/browser/sync/sync_setup_service_factory.h"
#import "ios/chrome/browser/sync/sync_setup_service_mock.h"
#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h"
#import "ios/chrome/browser/ui/recent_tabs/sessions_sync_user_state.h"
#import "ios/chrome/test/block_cleanup_test.h"
#import "ios/chrome/test/ios_chrome_scoped_testing_local_state.h"
#import "ios/chrome/test/scoped_key_window.h"
#import "ios/web/public/test/web_task_environment.h"
#import "testing/gtest/include/gtest/gtest.h"
#import "third_party/ocmock/OCMock/OCMock.h"
#import "third_party/ocmock/gtest_support.h"
#import "url/gurl.h"
using testing::_;
using testing::DoAll;
using testing::Return;
using testing::SetArgPointee;
namespace {
class SessionSyncServiceMockForRecentTabsTableCoordinator
: public sync_sessions::SessionSyncService {
public:
SessionSyncServiceMockForRecentTabsTableCoordinator() {}
~SessionSyncServiceMockForRecentTabsTableCoordinator() override {}
MOCK_CONST_METHOD0(GetGlobalIdMapper, syncer::GlobalIdMapper*());
MOCK_METHOD0(GetOpenTabsUIDelegate, sync_sessions::OpenTabsUIDelegate*());
MOCK_METHOD1(
SubscribeToForeignSessionsChanged,
base::CallbackListSubscription(const base::RepeatingClosure& cb));
MOCK_METHOD0(ScheduleGarbageCollection, void());
MOCK_METHOD0(GetControllerDelegate,
base::WeakPtr<syncer::ModelTypeControllerDelegate>());
MOCK_METHOD1(ProxyTabsStateChanged,
void(syncer::DataTypeController::State state));
};
std::unique_ptr<KeyedService>
BuildMockSessionSyncServiceForRecentTabsTableCoordinator(
web::BrowserState* context) {
return std::make_unique<
testing::NiceMock<SessionSyncServiceMockForRecentTabsTableCoordinator>>();
}
// Returns a TestSyncService.
std::unique_ptr<KeyedService> BuildFakeSyncServiceFactory(
web::BrowserState* context) {
return std::make_unique<syncer::TestSyncService>();
}
class OpenTabsUIDelegateMock : public sync_sessions::OpenTabsUIDelegate {
public:
OpenTabsUIDelegateMock() {}
~OpenTabsUIDelegateMock() override {}
MOCK_METHOD1(
GetAllForeignSessions,
bool(std::vector<const sync_sessions::SyncedSession*>* sessions));
MOCK_METHOD3(GetForeignTab,
bool(const std::string& tag,
const SessionID tab_id,
const sessions::SessionTab** tab));
MOCK_METHOD1(DeleteForeignSession, void(const std::string& tag));
MOCK_METHOD2(GetForeignSession,
bool(const std::string& tag,
std::vector<const sessions::SessionWindow*>* windows));
MOCK_METHOD2(GetForeignSessionTabs,
bool(const std::string& tag,
std::vector<const sessions::SessionTab*>* tabs));
MOCK_METHOD1(GetLocalSession,
bool(const sync_sessions::SyncedSession** local));
};
class GlobalIdMapperMock : public syncer::GlobalIdMapper {
public:
GlobalIdMapperMock() {}
~GlobalIdMapperMock() {}
MOCK_METHOD1(AddGlobalIdChangeObserver,
void(syncer::GlobalIdChange callback));
MOCK_METHOD1(GetLatestGlobalId, int64_t(int64_t global_id));
};
class RecentTabsTableCoordinatorTest : public BlockCleanupTest {
public:
RecentTabsTableCoordinatorTest()
: no_error_(GoogleServiceAuthError::NONE),
fake_controller_delegate_(syncer::SESSIONS) {}
protected:
void SetUp() override {
BlockCleanupTest::SetUp();
TestChromeBrowserState::Builder test_cbs_builder;
test_cbs_builder.AddTestingFactory(
SyncSetupServiceFactory::GetInstance(),
base::BindRepeating(&SyncSetupServiceMock::CreateKeyedService));
test_cbs_builder.AddTestingFactory(
ios::FaviconServiceFactory::GetInstance(),
ios::FaviconServiceFactory::GetDefaultFactory());
test_cbs_builder.AddTestingFactory(
AuthenticationServiceFactory::GetInstance(),
AuthenticationServiceFactory::GetDefaultFactory());
test_cbs_builder.AddTestingFactory(
IOSChromeLargeIconServiceFactory::GetInstance(),
IOSChromeLargeIconServiceFactory::GetDefaultFactory());
test_cbs_builder.AddTestingFactory(
IOSChromeFaviconLoaderFactory::GetInstance(),
IOSChromeFaviconLoaderFactory::GetDefaultFactory());
test_cbs_builder.AddTestingFactory(
ios::HistoryServiceFactory::GetInstance(),
ios::HistoryServiceFactory::GetDefaultFactory());
test_cbs_builder.AddTestingFactory(
SyncServiceFactory::GetInstance(),
base::BindRepeating(&BuildFakeSyncServiceFactory));
test_cbs_builder.AddTestingFactory(
SessionSyncServiceFactory::GetInstance(),
base::BindRepeating(
&BuildMockSessionSyncServiceForRecentTabsTableCoordinator));
test_cbs_builder.AddTestingFactory(
IOSChromeTabRestoreServiceFactory::GetInstance(),
IOSChromeTabRestoreServiceFactory::GetDefaultFactory());
chrome_browser_state_ = test_cbs_builder.Build();
AuthenticationServiceFactory::CreateAndInitializeForBrowserState(
chrome_browser_state_.get(),
std::make_unique<FakeAuthenticationServiceDelegate>());
browser_ = std::make_unique<TestBrowser>(chrome_browser_state_.get());
}
void TearDown() override {
[coordinator_ stop];
coordinator_ = nil;
BlockCleanupTest::TearDown();
}
void SetupSyncState(BOOL signed_in,
BOOL sync_enabled,
BOOL sync_completed,
BOOL has_foreign_sessions) {
SessionSyncServiceMockForRecentTabsTableCoordinator* session_sync_service =
static_cast<SessionSyncServiceMockForRecentTabsTableCoordinator*>(
SessionSyncServiceFactory::GetForBrowserState(
chrome_browser_state_.get()));
syncer::TestSyncService* sync_service =
static_cast<syncer::TestSyncService*>(
SyncServiceFactory::GetForBrowserState(
chrome_browser_state_.get()));
sync_service->SetSetupInProgress(!sync_enabled);
sync_service->SetHasSyncConsent(sync_completed);
// Needed by SyncService's initialization, triggered during initialization
// of SyncSetupServiceMock.
ON_CALL(*session_sync_service, GetControllerDelegate())
.WillByDefault(Return(fake_controller_delegate_.GetWeakPtr()));
ON_CALL(*session_sync_service, GetGlobalIdMapper())
.WillByDefault(Return(&global_id_mapper_));
SyncSetupServiceMock* syncSetupService = static_cast<SyncSetupServiceMock*>(
SyncSetupServiceFactory::GetForBrowserState(
chrome_browser_state_.get()));
ON_CALL(*syncSetupService,
IsDataTypePreferred(syncer::UserSelectableType::kTabs))
.WillByDefault(Return(true));
if (signed_in) {
AuthenticationService* authentication_service =
AuthenticationServiceFactory::GetForBrowserState(
chrome_browser_state_.get());
FakeSystemIdentity* identity = [FakeSystemIdentity fakeIdentity1];
// Register a fake identity and set the expected capabilities.
FakeSystemIdentityManager* system_identity_manager =
FakeSystemIdentityManager::FromSystemIdentityManager(
GetApplicationContext()->GetSystemIdentityManager());
system_identity_manager->AddIdentity(identity);
authentication_service->SignIn(
identity, signin_metrics::AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR);
authentication_service->GrantSyncConsent(
identity, signin_metrics::AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR);
}
ON_CALL(*session_sync_service, GetOpenTabsUIDelegate())
.WillByDefault(Return(&open_tabs_ui_delegate_));
if (has_foreign_sessions) {
sessions_.push_back(&sync_session_);
open_tab_.navigations.push_back(
sessions::SerializedNavigationEntryTestHelper::
CreateNavigationForTest());
open_tabs_.push_back(&open_tab_);
ON_CALL(open_tabs_ui_delegate_, GetForeignSessionTabs(_, _))
.WillByDefault(DoAll(SetArgPointee<1>(open_tabs_), Return(true)));
}
ON_CALL(open_tabs_ui_delegate_, GetAllForeignSessions(_))
.WillByDefault(
DoAll(SetArgPointee<0>(sessions_), Return(has_foreign_sessions)));
}
void CreateController() {
base_view_controller_ = [[UIViewController alloc] init];
[scoped_key_window_.Get() setRootViewController:base_view_controller_];
coordinator_ = [[RecentTabsCoordinator alloc]
initWithBaseViewController:base_view_controller_
browser:browser_.get()];
mock_application_commands_handler_ =
[OCMockObject mockForProtocol:@protocol(ApplicationCommands)];
mock_application_settings_commands_handler_ =
[OCMockObject mockForProtocol:@protocol(ApplicationSettingsCommands)];
mock_browsing_data_commands_handler_ =
[OCMockObject mockForProtocol:@protocol(BrowsingDataCommands)];
[browser_->GetCommandDispatcher()
startDispatchingToTarget:mock_application_commands_handler_
forProtocol:@protocol(ApplicationCommands)];
[browser_->GetCommandDispatcher()
startDispatchingToTarget:mock_application_settings_commands_handler_
forProtocol:@protocol(ApplicationSettingsCommands)];
[browser_->GetCommandDispatcher()
startDispatchingToTarget:mock_browsing_data_commands_handler_
forProtocol:@protocol(BrowsingDataCommands)];
[coordinator_ start];
ASSERT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::Milliseconds(100), ^bool {
return base_view_controller_.presentedViewController != nil;
}));
base::test::ios::SpinRunLoopWithMinDelay(base::Milliseconds(100));
}
protected:
web::WebTaskEnvironment task_environment_;
GoogleServiceAuthError no_error_;
IOSChromeScopedTestingLocalState local_state_;
syncer::FakeModelTypeControllerDelegate fake_controller_delegate_;
testing::NiceMock<OpenTabsUIDelegateMock> open_tabs_ui_delegate_;
testing::NiceMock<GlobalIdMapperMock> global_id_mapper_;
std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
std::unique_ptr<Browser> browser_;
ScopedKeyWindow scoped_key_window_;
UIViewController* base_view_controller_;
sync_sessions::SyncedSession sync_session_;
std::vector<const sync_sessions::SyncedSession*> sessions_;
sessions::SessionTab open_tab_;
std::vector<const sessions::SessionTab*> open_tabs_;
// Must be declared *after* `chrome_browser_state_` so it can outlive it.
RecentTabsCoordinator* coordinator_;
id<ApplicationCommands> mock_application_commands_handler_;
id<ApplicationSettingsCommands> mock_application_settings_commands_handler_;
id<BrowsingDataCommands> mock_browsing_data_commands_handler_;
};
TEST_F(RecentTabsTableCoordinatorTest, TestConstructorDestructor) {
SetupSyncState(NO, NO, NO, NO);
CreateController();
EXPECT_TRUE(coordinator_);
}
TEST_F(RecentTabsTableCoordinatorTest, TestUserSignedOut) {
// TODO(crbug.com/907495): Actual test expectations are missing below.
SetupSyncState(NO, NO, NO, NO);
CreateController();
}
TEST_F(RecentTabsTableCoordinatorTest, TestUserSignedInSyncOff) {
// TODO(crbug.com/907495): Actual test expectations are missing below.
SetupSyncState(YES, NO, NO, NO);
CreateController();
}
TEST_F(RecentTabsTableCoordinatorTest, TestUserSignedInSyncInProgress) {
// TODO(crbug.com/907495): Actual test expectations are missing below.
SetupSyncState(YES, YES, NO, NO);
CreateController();
}
TEST_F(RecentTabsTableCoordinatorTest, TestUserSignedInSyncOnWithoutSessions) {
// TODO(crbug.com/907495): Actual test expectations are missing below.
SetupSyncState(YES, YES, YES, NO);
CreateController();
}
TEST_F(RecentTabsTableCoordinatorTest, TestUserSignedInSyncOnWithSessions) {
// TODO(crbug.com/907495): Actual test expectations are missing below.
SetupSyncState(YES, YES, YES, YES);
CreateController();
}
// Makes sure that the app don't crash when checking cells after -stop is
// called. This is done to prevent crbug.com/1469608 to regress.
TEST_F(RecentTabsTableCoordinatorTest, TestLoadFaviconAfterDisconnect) {
SetupSyncState(YES, YES, YES, YES);
CreateController();
UINavigationController* navigation_controller =
base::apple::ObjCCastStrict<UINavigationController>(
base_view_controller_.presentedViewController);
RecentTabsTableViewController* view_controller =
base::apple::ObjCCastStrict<RecentTabsTableViewController>(
navigation_controller.topViewController);
[coordinator_ stop];
for (NSInteger section_index = 0;
section_index <
[view_controller numberOfSectionsInTableView:view_controller.tableView];
section_index++) {
for (NSInteger row_index = 0;
row_index < [view_controller tableView:view_controller.tableView
numberOfRowsInSection:section_index];
row_index++) {
[view_controller tableView:view_controller.tableView
cellForRowAtIndexPath:[NSIndexPath indexPathForRow:row_index
inSection:section_index]];
}
}
}
} // namespace