| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ios/chrome/app/application_delegate/metrics_mediator.h" |
| #import "ios/chrome/app/application_delegate/metrics_mediator_testing.h" |
| |
| #import <Foundation/Foundation.h> |
| |
| #include "components/metrics/metrics_service.h" |
| #import "components/previous_session_info/previous_session_info.h" |
| #import "components/previous_session_info/previous_session_info_private.h" |
| #import "ios/chrome/app/application_delegate/startup_information.h" |
| #include "ios/chrome/browser/application_context.h" |
| #include "ios/chrome/browser/chrome_url_constants.h" |
| #import "ios/chrome/browser/main/test_browser.h" |
| #import "ios/chrome/browser/ui/main/browser_interface_provider.h" |
| #import "ios/chrome/browser/ui/main/scene_state.h" |
| #import "ios/chrome/browser/ui/main/test/fake_scene_state.h" |
| #import "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.h" |
| #import "ios/chrome/browser/web_state_list/web_state_list.h" |
| #import "ios/chrome/browser/web_state_list/web_state_opener.h" |
| #import "ios/chrome/test/ocmock/OCMockObject+BreakpadControllerTesting.h" |
| #import "ios/testing/scoped_block_swizzler.h" |
| #import "ios/web/public/test/web_task_environment.h" |
| #include "net/base/network_change_notifier.h" |
| #include "testing/platform_test.h" |
| #import "third_party/ocmock/OCMock/OCMock.h" |
| #include "third_party/ocmock/gtest_support.h" |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| #pragma mark - connectionTypeChanged tests. |
| |
| // Mock class for testing MetricsMediator. |
| @interface MetricsMediatorMock : MetricsMediator |
| @property(nonatomic) NSInteger reportingValue; |
| @property(nonatomic) NSInteger breakpadUpload; |
| - (void)reset; |
| - (void)setReporting:(BOOL)enableReporting; |
| @end |
| |
| @implementation MetricsMediatorMock |
| @synthesize reportingValue = _reportingValue; |
| @synthesize breakpadUpload = _breakpadUpload; |
| |
| - (void)reset { |
| _reportingValue = -1; |
| _breakpadUpload = -1; |
| } |
| - (void)setBreakpadUploadingEnabled:(BOOL)enableUploading { |
| _breakpadUpload = enableUploading ? 1 : 0; |
| } |
| - (void)setReporting:(BOOL)enableReporting { |
| _reportingValue = enableReporting ? 1 : 0; |
| } |
| - (BOOL)isMetricsReportingEnabledWifiOnly { |
| return YES; |
| } |
| - (BOOL)areMetricsEnabled { |
| return YES; |
| } |
| |
| @end |
| |
| // Gives the differents net::NetworkChangeNotifier::ConnectionType based on |
| // scenario number. |
| net::NetworkChangeNotifier::ConnectionType getConnectionType(int number) { |
| switch (number) { |
| case 0: |
| return net::NetworkChangeNotifier::CONNECTION_UNKNOWN; |
| case 1: |
| return net::NetworkChangeNotifier::CONNECTION_ETHERNET; |
| case 2: |
| return net::NetworkChangeNotifier::CONNECTION_WIFI; |
| case 3: |
| return net::NetworkChangeNotifier::CONNECTION_2G; |
| case 4: |
| return net::NetworkChangeNotifier::CONNECTION_3G; |
| case 5: |
| return net::NetworkChangeNotifier::CONNECTION_4G; |
| case 6: |
| return net::NetworkChangeNotifier::CONNECTION_NONE; |
| case 7: |
| return net::NetworkChangeNotifier::CONNECTION_BLUETOOTH; |
| case 8: |
| return net::NetworkChangeNotifier::CONNECTION_5G; |
| default: |
| return net::NetworkChangeNotifier::CONNECTION_UNKNOWN; |
| } |
| } |
| |
| // Gives the differents expected value based on scenario number. |
| int getExpectedValue(int number) { |
| // Cellular network types are expected to return 0. |
| switch (getConnectionType(number)) { |
| case net::NetworkChangeNotifier::CONNECTION_2G: |
| case net::NetworkChangeNotifier::CONNECTION_3G: |
| case net::NetworkChangeNotifier::CONNECTION_4G: |
| case net::NetworkChangeNotifier::CONNECTION_5G: |
| return 0; |
| default: |
| return 1; |
| } |
| } |
| |
| using MetricsMediatorTest = PlatformTest; |
| |
| // Verifies that connectionTypeChanged correctly enables or disables the |
| // uploading in the breakpad and in the metrics service. |
| TEST_F(MetricsMediatorTest, connectionTypeChanged) { |
| [[PreviousSessionInfo sharedInstance] setIsFirstSessionAfterUpgrade:NO]; |
| MetricsMediatorMock* mock_metrics_helper = [[MetricsMediatorMock alloc] init]; |
| |
| // Checks all different scenarios. |
| for (int i = 0; i < 9; ++i) { |
| [mock_metrics_helper reset]; |
| [mock_metrics_helper connectionTypeChanged:getConnectionType(i)]; |
| EXPECT_EQ(getExpectedValue(i), [mock_metrics_helper reportingValue]); |
| EXPECT_EQ(getExpectedValue(i), [mock_metrics_helper breakpadUpload]); |
| } |
| |
| // Checks that no new ConnectionType has been added. |
| EXPECT_EQ(net::NetworkChangeNotifier::CONNECTION_5G, |
| net::NetworkChangeNotifier::CONNECTION_LAST); |
| } |
| |
| #pragma mark - logLaunchMetrics tests. |
| |
| // A block that takes as arguments the caller and the arguments from |
| // UserActivityHandler +handleStartupParameters and returns nothing. |
| typedef void (^LogLaunchMetricsBlock)(id, const char*, int); |
| |
| class MetricsMediatorLogLaunchTest : public PlatformTest { |
| protected: |
| MetricsMediatorLogLaunchTest() |
| : num_tabs_has_been_called_(FALSE), |
| num_ntp_tabs_has_been_called_(FALSE) {} |
| |
| void initiateMetricsMediator(BOOL coldStart, int tabCount) { |
| num_tabs_swizzle_block_ = [^(id self, int numTab) { |
| num_tabs_has_been_called_ = YES; |
| // Tests. |
| EXPECT_EQ(tabCount, numTab); |
| } copy]; |
| num_ntp_tabs_swizzle_block_ = [^(id self, int numTab) { |
| num_ntp_tabs_has_been_called_ = YES; |
| // Tests. |
| EXPECT_EQ(tabCount, numTab); |
| } copy]; |
| if (coldStart) { |
| tabs_uma_histogram_swizzler_.reset(new ScopedBlockSwizzler( |
| [MetricsMediator class], @selector(recordNumTabAtStartup:), |
| num_tabs_swizzle_block_)); |
| ntp_tabs_uma_histogram_swizzler_.reset(new ScopedBlockSwizzler( |
| [MetricsMediator class], @selector(recordNumNTPTabAtStartup:), |
| num_ntp_tabs_swizzle_block_)); |
| } else { |
| tabs_uma_histogram_swizzler_.reset(new ScopedBlockSwizzler( |
| [MetricsMediator class], @selector(recordNumTabAtResume:), |
| num_tabs_swizzle_block_)); |
| ntp_tabs_uma_histogram_swizzler_.reset(new ScopedBlockSwizzler( |
| [MetricsMediator class], @selector(recordNumNTPTabAtResume:), |
| num_ntp_tabs_swizzle_block_)); |
| } |
| } |
| |
| void verifySwizzleHasBeenCalled() { |
| EXPECT_TRUE(num_tabs_has_been_called_); |
| EXPECT_TRUE(num_ntp_tabs_has_been_called_); |
| } |
| |
| web::WebTaskEnvironment task_environment_; |
| NSArray<FakeSceneState*>* connected_scenes_; |
| __block BOOL num_tabs_has_been_called_; |
| __block BOOL num_ntp_tabs_has_been_called_; |
| LogLaunchMetricsBlock num_tabs_swizzle_block_; |
| LogLaunchMetricsBlock num_ntp_tabs_swizzle_block_; |
| std::unique_ptr<ScopedBlockSwizzler> tabs_uma_histogram_swizzler_; |
| std::unique_ptr<ScopedBlockSwizzler> ntp_tabs_uma_histogram_swizzler_; |
| std::set<std::unique_ptr<TestBrowser>> browsers_; |
| }; |
| |
| // Verifies that the log of the number of open tabs is sent and verifies |
| TEST_F(MetricsMediatorLogLaunchTest, |
| logLaunchMetricsWithEnteredBackgroundDate) { |
| // Setup. |
| BOOL coldStart = YES; |
| initiateMetricsMediator(coldStart, 23); |
| // 23 tabs across three scenes. |
| connected_scenes_ = [FakeSceneState sceneArrayWithCount:3]; |
| [connected_scenes_[0] appendWebStatesWithURL:GURL(kChromeUINewTabURL) |
| count:9]; |
| [connected_scenes_[1] appendWebStatesWithURL:GURL(kChromeUINewTabURL) |
| count:9]; |
| [connected_scenes_[2] appendWebStatesWithURL:GURL(kChromeUINewTabURL) |
| count:5]; |
| // Mark one of the scenes as active. |
| connected_scenes_[0].activationLevel = SceneActivationLevelForegroundActive; |
| |
| const NSTimeInterval kFirstUserActionTimeout = 30.0; |
| |
| id startupInformation = |
| [OCMockObject niceMockForProtocol:@protocol(StartupInformation)]; |
| [[[startupInformation stub] andReturnValue:@(coldStart)] isColdStart]; |
| [[startupInformation expect] |
| expireFirstUserActionRecorderAfterDelay:kFirstUserActionTimeout]; |
| |
| [[NSUserDefaults standardUserDefaults] |
| setObject:[NSDate date] |
| forKey:metrics_mediator::kAppEnteredBackgroundDateKey]; |
| |
| // Action. |
| [MetricsMediator logLaunchMetricsWithStartupInformation:startupInformation |
| connectedScenes:connected_scenes_]; |
| |
| // Tests. |
| NSDate* dateStored = [[NSUserDefaults standardUserDefaults] |
| objectForKey:metrics_mediator::kAppEnteredBackgroundDateKey]; |
| EXPECT_EQ(nil, dateStored); |
| verifySwizzleHasBeenCalled(); |
| EXPECT_OCMOCK_VERIFY(startupInformation); |
| } |
| |
| // Verifies that +logLaunchMetrics logs of the number of open tabs and nothing |
| // more if the background date is not set; |
| TEST_F(MetricsMediatorLogLaunchTest, logLaunchMetricsNoBackgroundDate) { |
| // Setup. |
| BOOL coldStart = NO; |
| initiateMetricsMediator(coldStart, 32); |
| // 32 tabs across five scenes. |
| connected_scenes_ = [FakeSceneState sceneArrayWithCount:5]; |
| [connected_scenes_[0] appendWebStatesWithURL:GURL(kChromeUINewTabURL) |
| count:8]; |
| [connected_scenes_[1] appendWebStatesWithURL:GURL(kChromeUINewTabURL) |
| count:8]; |
| // Scene 2 has zero tabs. |
| [connected_scenes_[3] appendWebStatesWithURL:GURL(kChromeUINewTabURL) |
| count:8]; |
| [connected_scenes_[4] appendWebStatesWithURL:GURL(kChromeUINewTabURL) |
| count:8]; |
| |
| id startupInformation = |
| [OCMockObject mockForProtocol:@protocol(StartupInformation)]; |
| [[[startupInformation stub] andReturnValue:@(coldStart)] isColdStart]; |
| |
| [[NSUserDefaults standardUserDefaults] |
| removeObjectForKey:metrics_mediator::kAppEnteredBackgroundDateKey]; |
| |
| // Action. |
| [MetricsMediator logLaunchMetricsWithStartupInformation:startupInformation |
| connectedScenes:connected_scenes_]; |
| // Tests. |
| verifySwizzleHasBeenCalled(); |
| } |
| |
| using MetricsMediatorNoFixtureTest = PlatformTest; |
| |
| // Tests that +logDateInUserDefaults logs the date in UserDefaults. |
| TEST_F(MetricsMediatorNoFixtureTest, logDateInUserDefaultsTest) { |
| // Setup. |
| [[NSUserDefaults standardUserDefaults] |
| removeObjectForKey:metrics_mediator::kAppEnteredBackgroundDateKey]; |
| |
| NSDate* lastAppClose = [[NSUserDefaults standardUserDefaults] |
| objectForKey:metrics_mediator::kAppEnteredBackgroundDateKey]; |
| |
| ASSERT_EQ(nil, lastAppClose); |
| |
| // Action. |
| [MetricsMediator logDateInUserDefaults]; |
| |
| // Setup. |
| lastAppClose = [[NSUserDefaults standardUserDefaults] |
| objectForKey:metrics_mediator::kAppEnteredBackgroundDateKey]; |
| EXPECT_NE(nil, lastAppClose); |
| } |
| |