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

#include "chrome/browser/ash/login/enterprise_user_session_metrics.h"

#include <memory>

#include "base/check_deref.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/time/time.h"
#include "chrome/browser/ash/login/demo_mode/demo_session.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chromeos/ash/components/install_attributes/stub_install_attributes.h"
#include "chromeos/ash/components/login/auth/public/user_context.h"
#include "components/account_id/account_id.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace ash {

// Tests enterprise session start/stop metrics recording.
// TODO(michaelpg): Add browser tests to verify the methods are called at the
// right times.
class EnterpriseUserSessionMetricsTest : public testing::Test {
 public:
  EnterpriseUserSessionMetricsTest()
      : install_attributes_(std::make_unique<ScopedStubInstallAttributes>(
            StubInstallAttributes::CreateCloudManaged("test-domain",
                                                      "FAKE_DEVICE_ID"))) {}

  EnterpriseUserSessionMetricsTest(const EnterpriseUserSessionMetricsTest&) =
      delete;
  EnterpriseUserSessionMetricsTest& operator=(
      const EnterpriseUserSessionMetricsTest&) = delete;

  ~EnterpriseUserSessionMetricsTest() override = default;

 protected:
  content::BrowserTaskEnvironment task_environment_;
  std::unique_ptr<ScopedStubInstallAttributes> install_attributes_;
};

// Tests recording session length.
TEST_F(EnterpriseUserSessionMetricsTest, RecordSessionLength) {
  {
    SCOPED_TRACE("");
    base::HistogramTester histogram_tester;
    enterprise_user_session_metrics::StoreSessionLength(
        CHECK_DEREF(TestingBrowserProcess::GetGlobal()->local_state()),
        user_manager::UserType::kPublicAccount, base::Minutes(25));
    enterprise_user_session_metrics::RecordStoredSessionLength(
        CHECK_DEREF(TestingBrowserProcess::GetGlobal()->local_state()));

    // Time is rounded down to the nearest 10.
    histogram_tester.ExpectUniqueSample(
        "Enterprise.PublicSession.SessionLength", 20, 1);

    // No other session length metrics are recorded.
    histogram_tester.ExpectTotalCount(
        "Enterprise.RegularUserSession.SessionLength", 0);
    histogram_tester.ExpectTotalCount("DemoMode.SessionLength", 0);
  }
  {
    SCOPED_TRACE("");
    // Test with a regular user session.
    base::HistogramTester histogram_tester;
    enterprise_user_session_metrics::StoreSessionLength(
        CHECK_DEREF(TestingBrowserProcess::GetGlobal()->local_state()),
        user_manager::UserType::kRegular, base::Minutes(149));
    enterprise_user_session_metrics::RecordStoredSessionLength(
        CHECK_DEREF(TestingBrowserProcess::GetGlobal()->local_state()));
    histogram_tester.ExpectUniqueSample(
        "Enterprise.RegularUserSession.SessionLength", 140, 1);

    // No other session length metrics are recorded.
    histogram_tester.ExpectTotalCount("Enterprise.PublicSession.SessionLength",
                                      0);
    histogram_tester.ExpectTotalCount("DemoMode.SessionLength", 0);
  }
  {
    SCOPED_TRACE("");
    base::HistogramTester histogram_tester;
    enterprise_user_session_metrics::StoreSessionLength(
        CHECK_DEREF(TestingBrowserProcess::GetGlobal()->local_state()),
        user_manager::UserType::kRegular, base::Days(10));
    enterprise_user_session_metrics::RecordStoredSessionLength(
        CHECK_DEREF(TestingBrowserProcess::GetGlobal()->local_state()));

    // Reported length is capped at 24 hours.
    histogram_tester.ExpectUniqueSample(
        "Enterprise.RegularUserSession.SessionLength",
        base::Hours(24).InMinutes(), 1);

    // No other session length metrics are recorded.
    histogram_tester.ExpectTotalCount("Enterprise.PublicSession.SessionLength",
                                      0);
    histogram_tester.ExpectTotalCount("DemoMode.SessionLength", 0);
  }
  {
    SCOPED_TRACE("");
    // Test with no session. This verifies the same metric isn't recorded twice
    // if something goes wrong.
    base::HistogramTester histogram_tester;
    enterprise_user_session_metrics::RecordStoredSessionLength(
        CHECK_DEREF(TestingBrowserProcess::GetGlobal()->local_state()));
    histogram_tester.ExpectTotalCount("Enterprise.PublicSession.SessionLength",
                                      0);
    histogram_tester.ExpectTotalCount(
        "Enterprise.RegularUserSession.SessionLength", 0);
    histogram_tester.ExpectTotalCount("DemoMode.SessionLength", 0);
  }
}

// Tests recording session length in demo sessions, which includes an additional
// metric with tighter bucket spacing.
TEST_F(EnterpriseUserSessionMetricsTest, RecordDemoSessionLength) {
  install_attributes_->Get()->SetDemoMode();
  {
    SCOPED_TRACE("");
    base::HistogramTester histogram_tester;
    enterprise_user_session_metrics::StoreSessionLength(
        CHECK_DEREF(TestingBrowserProcess::GetGlobal()->local_state()),
        user_manager::UserType::kPublicAccount, base::Seconds(25 * 60 + 59));
    enterprise_user_session_metrics::RecordStoredSessionLength(
        CHECK_DEREF(TestingBrowserProcess::GetGlobal()->local_state()));

    // Time is rounded down to the nearest 10 minutes.
    histogram_tester.ExpectUniqueSample(
        "Enterprise.PublicSession.SessionLength", 20, 1);

    // The demo mode session length metric is rounded down to the nearest
    // minute.
    histogram_tester.ExpectUniqueSample("DemoMode.SessionLength", 25, 1);
  }
  {
    SCOPED_TRACE("");
    base::HistogramTester histogram_tester;
    enterprise_user_session_metrics::StoreSessionLength(
        CHECK_DEREF(TestingBrowserProcess::GetGlobal()->local_state()),
        user_manager::UserType::kPublicAccount, base::Days(10));
    enterprise_user_session_metrics::RecordStoredSessionLength(
        CHECK_DEREF(TestingBrowserProcess::GetGlobal()->local_state()));

    // Reported length is capped at 24 hours.
    histogram_tester.ExpectUniqueSample(
        "Enterprise.PublicSession.SessionLength", base::Hours(24).InMinutes(),
        1);

    // Demo session length is capped at 2 hours because demo sessions are short.
    histogram_tester.ExpectUniqueSample("DemoMode.SessionLength",
                                        base::Hours(2).InMinutes(), 1);
  }
  {
    SCOPED_TRACE("");
    // Test with no session. This verifies the same metric isn't recorded twice
    // if something goes wrong.
    base::HistogramTester histogram_tester;
    enterprise_user_session_metrics::RecordStoredSessionLength(
        CHECK_DEREF(TestingBrowserProcess::GetGlobal()->local_state()));
    histogram_tester.ExpectTotalCount("Enterprise.PublicSession.SessionLength",
                                      0);
    histogram_tester.ExpectTotalCount(
        "Enterprise.RegularUserSession.SessionLength", 0);
    histogram_tester.ExpectTotalCount("DemoMode.SessionLength", 0);
  }
}

}  // namespace ash
