chromium/android_webview/browser/metrics/aw_metrics_service_client_unittest.cc

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "android_webview/browser/metrics/aw_metrics_service_client.h"

#include <memory>

#include "android_webview/common/aw_features.h"
#include "base/metrics/histogram.h"
#include "base/metrics/user_metrics.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/test/test_simple_task_runner.h"
#include "base/time/time.h"
#include "base/version.h"
#include "components/embedder_support/android/metrics/android_metrics_service_client.h"
#include "components/metrics/content/subprocess_metrics_provider.h"
#include "components/metrics/metrics_switches.h"
#include "components/prefs/testing_pref_service.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_content_client_initializer.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace android_webview {

using InstallerPackageType =
    metrics::AndroidMetricsServiceClient::InstallerPackageType;

namespace {

class AwMetricsServiceClientTestDelegate
    : public AwMetricsServiceClient::Delegate {
  void RegisterAdditionalMetricsProviders(
      metrics::MetricsService* service) override {}
  void AddWebViewAppStateObserver(WebViewAppStateObserver* observer) override {}
  bool HasAwContentsEverCreated() const override { return false; }
};

// Adds support for setting whether metric reporting is in sample.
class AwMetricsServiceTestClient : public AwMetricsServiceClient {
 public:
  explicit AwMetricsServiceTestClient(std::unique_ptr<Delegate> delegate)
      : AwMetricsServiceClient(std::move(delegate)) {}
  void SetInSample(bool in_sample) { in_sample_ = in_sample; }
  void SetSampleBucketValue(int sample_bucket_value) {
    sample_bucket_value_ = sample_bucket_value;
  }

 protected:
  bool IsInSample() const override { return in_sample_; }
  int GetSampleBucketValue() const override { return sample_bucket_value_; }

 private:
  bool in_sample_ = false;
  int sample_bucket_value_ = 0;
};

class AwMetricsServiceClientTest : public testing::Test {
  AwMetricsServiceClientTest& operator=(const AwMetricsServiceClientTest&) =
      delete;
  AwMetricsServiceClientTest(AwMetricsServiceClientTest&&) = delete;
  AwMetricsServiceClientTest& operator=(AwMetricsServiceClientTest&&) = delete;

 protected:
  AwMetricsServiceClientTest()
      : task_runner_(new base::TestSimpleTaskRunner),
        prefs_(std::make_unique<TestingPrefServiceSimple>()),
        client_(std::make_unique<AwMetricsServiceTestClient>(
            std::make_unique<AwMetricsServiceClientTestDelegate>())) {
    base::SetRecordActionTaskRunner(task_runner_);
    AwMetricsServiceTestClient::RegisterMetricsPrefs(prefs_->registry());
    // Needed because RegisterMetricsProvidersAndInitState() checks for this.
    metrics::SubprocessMetricsProvider::CreateInstance();

    client_->Initialize(prefs_.get());
  }

  AwMetricsServiceTestClient* GetClient() { return client_.get(); }
  TestingPrefServiceSimple* GetPrefs() { return prefs_.get(); }

  void TriggerDelayedRecordAppDataDirectorySize() {
    task_environment_.FastForwardBy(kRecordAppDataDirectorySizeDelay);
  }

 private:
  // Needed since starting metrics reporting triggers code that uses content::
  // objects.
  content::TestContentClientInitializer test_content_initializer_;
  // Needed since starting metrics reporting triggers code that expects to be
  // running on the browser UI thread. Also needed for its FastForwardBy method.
  content::BrowserTaskEnvironment task_environment_{
      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
  std::unique_ptr<TestingPrefServiceSimple> prefs_;
  std::unique_ptr<AwMetricsServiceTestClient> client_;
};

}  // namespace

TEST_F(AwMetricsServiceClientTest, TestShouldRecordPackageName) {
  AwMetricsServiceClient* client = GetClient();
  EXPECT_TRUE(client->ShouldRecordPackageName());
}

TEST_F(
    AwMetricsServiceClientTest,
    TestAppDataDirectorySize_RecordedIfFeatureEnabledConsentGrantedAndInSample) {
  base::test::ScopedFeatureList scoped_list;
  scoped_list.InitAndEnableFeature(
      android_webview::features::kWebViewRecordAppDataDirectorySize);
  base::HistogramTester histogram_tester;

  GetClient()->SetInSample(true);
  GetClient()->SetHaveMetricsConsent(true, true);
  TriggerDelayedRecordAppDataDirectorySize();

  histogram_tester.ExpectTotalCount("Android.WebView.AppDataDirectory.Size", 1);
  histogram_tester.ExpectTotalCount(
      "Android.WebView.AppDataDirectory.TimeToComputeSize", 1);
}

TEST_F(AwMetricsServiceClientTest,
       TestAppDataDirectorySize_NotRecordedIfFeatureDisabled) {
  base::test::ScopedFeatureList scoped_list;
  scoped_list.InitAndDisableFeature(
      android_webview::features::kWebViewRecordAppDataDirectorySize);
  base::HistogramTester histogram_tester;

  GetClient()->SetInSample(true);
  GetClient()->SetHaveMetricsConsent(true, true);
  TriggerDelayedRecordAppDataDirectorySize();

  histogram_tester.ExpectTotalCount("Android.WebView.AppDataDirectory,Size", 0);
  histogram_tester.ExpectTotalCount(
      "Android.WebView.AppDataDirectory.TimeToComputeSize", 0);
}

TEST_F(AwMetricsServiceClientTest,
       TestAppDataDirectorySize_NotRecordedIfConsentNotGranted) {
  base::test::ScopedFeatureList scoped_list;
  scoped_list.InitAndEnableFeature(
      android_webview::features::kWebViewRecordAppDataDirectorySize);
  base::HistogramTester histogram_tester;

  GetClient()->SetInSample(true);
  GetClient()->SetHaveMetricsConsent(true, false);
  TriggerDelayedRecordAppDataDirectorySize();

  histogram_tester.ExpectTotalCount("Android.WebView.AppDataDirectory.Size", 0);
  histogram_tester.ExpectTotalCount(
      "Android.WebView.AppDataDirectory.TimeToComputeSize", 0);
}

TEST_F(AwMetricsServiceClientTest,
       TestAppDataDirectorySize_NotRecordedIfNotInSample) {
  base::test::ScopedFeatureList scoped_list;
  scoped_list.InitAndEnableFeature(
      android_webview::features::kWebViewRecordAppDataDirectorySize);
  base::HistogramTester histogram_tester;

  GetClient()->SetInSample(false);
  GetClient()->SetHaveMetricsConsent(true, true);
  TriggerDelayedRecordAppDataDirectorySize();

  histogram_tester.ExpectTotalCount("Android.WebView.AppDataDirectory.Size", 0);
  histogram_tester.ExpectTotalCount(
      "Android.WebView.AppDataDirectory.TimeToComputeSize", 0);
}

TEST_F(AwMetricsServiceClientTest,
       TestShouldApplyMetricsFilteringFeatureOn_AllMetrics) {
  // Both metrics consent and app consent true;
  GetClient()->SetHaveMetricsConsent(true, true);
  GetClient()->SetSampleBucketValue(19);

  EXPECT_EQ(GetClient()->GetSampleRatePerMille(), 1000);
  EXPECT_FALSE(GetClient()->ShouldApplyMetricsFiltering());
}

TEST_F(AwMetricsServiceClientTest,
       TestShouldApplyMetricsFilteringFeatureOn_OnlyCriticalMetrics) {
  // Both metrics consent and app consent true;
  GetClient()->SetHaveMetricsConsent(true, true);
  GetClient()->SetSampleBucketValue(20);

  EXPECT_EQ(GetClient()->GetSampleRatePerMille(), 1000);
  EXPECT_TRUE(GetClient()->ShouldApplyMetricsFiltering());
}

}  // namespace android_webview