chromium/chrome/browser/ash/power/ml/user_activity_ukm_logger_unittest.cc

// Copyright 2017 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/power/ml/user_activity_ukm_logger_impl.h"

#include <memory>
#include <vector>

#include "chrome/browser/ash/power/ml/user_activity_event.pb.h"
#include "chrome/browser/ash/power/ml/user_activity_manager.h"
#include "components/ukm/test_ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace ash {
namespace power {
namespace ml {

using ukm::builders::UserActivity;
using ukm::builders::UserActivityId;

class UserActivityUkmLoggerTest : public testing::Test {
 public:
  UserActivityUkmLoggerTest() {
    // These values are arbitrary but must correspond with the values
    // in CheckUserActivityValues.
    UserActivityEvent::Event* event = user_activity_event_.mutable_event();
    event->set_log_duration_sec(395);
    event->set_reason(UserActivityEvent::Event::USER_ACTIVITY);
    event->set_type(UserActivityEvent::Event::REACTIVATE);
    event->set_screen_dim_occurred(true);
    event->set_screen_off_occurred(true);
    event->set_screen_lock_occurred(true);

    // In the order of metrics names in ukm.
    UserActivityEvent::Features* features =
        user_activity_event_.mutable_features();
    features->set_battery_percent(96.0);
    features->set_device_management(UserActivityEvent::Features::UNMANAGED);
    features->set_device_mode(UserActivityEvent::Features::CLAMSHELL);
    features->set_device_type(UserActivityEvent::Features::CHROMEBOOK);
    features->set_last_activity_day(UserActivityEvent::Features::MON);
    features->set_last_activity_time_sec(7300);
    features->set_last_user_activity_time_sec(3800);
    features->set_key_events_in_last_hour(20000);
    features->set_recent_time_active_sec(10);
    features->set_previous_negative_actions_count(2);
    features->set_previous_positive_actions_count(1);
    features->set_video_playing_time_sec(800);
    features->set_on_to_dim_sec(100);
    features->set_dim_to_screen_off_sec(200);
    features->set_screen_dimmed_initially(false);
    features->set_screen_locked_initially(false);
    features->set_screen_off_initially(false);
    features->set_time_since_last_mouse_sec(100);
    features->set_time_since_last_touch_sec(311);
    features->set_time_since_video_ended_sec(400);
    features->set_mouse_events_in_last_hour(89);
    features->set_touch_events_in_last_hour(1890);

    UserActivityEvent::ModelPrediction* prediction =
        user_activity_event_.mutable_model_prediction();
    prediction->set_decision_threshold(50);
    prediction->set_inactivity_score(60);
    prediction->set_model_applied(true);
    prediction->set_response(UserActivityEvent::ModelPrediction::NO_DIM);

    user_activity_logger_delegate_ukm_.ukm_recorder_ = &recorder_;
  }

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

 protected:
  void LogActivity(const UserActivityEvent& event) {
    user_activity_logger_delegate_ukm_.LogActivity(event);
  }

  void CheckUserActivityValues(const ukm::mojom::UkmEntry* entry) {
    recorder_.ExpectEntryMetric(entry, UserActivity::kEventLogDurationName,
                                395);
    recorder_.ExpectEntryMetric(entry, UserActivity::kEventReasonName,
                                UserActivityEvent::Event::USER_ACTIVITY);
    recorder_.ExpectEntryMetric(entry, UserActivity::kEventTypeName,
                                UserActivityEvent::Event::REACTIVATE);
    recorder_.ExpectEntryMetric(entry, UserActivity::kBatteryPercentName, 95);
    recorder_.ExpectEntryMetric(entry, UserActivity::kDeviceManagementName,
                                UserActivityEvent::Features::UNMANAGED);
    recorder_.ExpectEntryMetric(entry, UserActivity::kDeviceModeName,
                                UserActivityEvent::Features::CLAMSHELL);
    recorder_.ExpectEntryMetric(entry, UserActivity::kDeviceTypeName,
                                UserActivityEvent::Features::CHROMEBOOK);
    recorder_.ExpectEntryMetric(entry, UserActivity::kLastActivityDayName,
                                UserActivityEvent::Features::MON);
    recorder_.ExpectEntryMetric(entry, UserActivity::kKeyEventsInLastHourName,
                                10000);
    recorder_.ExpectEntryMetric(entry, UserActivity::kLastActivityTimeName, 2);
    recorder_.ExpectEntryMetric(entry, UserActivity::kLastUserActivityTimeName,
                                1);
    recorder_.ExpectEntryMetric(entry, UserActivity::kModelAppliedName, 1);
    recorder_.ExpectEntryMetric(entry,
                                UserActivity::kModelDecisionThresholdName, 50);
    recorder_.ExpectEntryMetric(entry, UserActivity::kModelInactivityScoreName,
                                60);
    recorder_.ExpectEntryMetric(entry, UserActivity::kModelResponseName, 1);
    recorder_.ExpectEntryMetric(entry, UserActivity::kMouseEventsInLastHourName,
                                89);
    EXPECT_FALSE(recorder_.EntryHasMetric(entry, UserActivity::kOnBatteryName));
    recorder_.ExpectEntryMetric(
        entry, UserActivity::kPreviousNegativeActionsCountName, 2);
    recorder_.ExpectEntryMetric(
        entry, UserActivity::kPreviousPositiveActionsCountName, 1);

    recorder_.ExpectEntryMetric(entry, UserActivity::kRecentTimeActiveName, 10);
    recorder_.ExpectEntryMetric(entry,
                                UserActivity::kRecentVideoPlayingTimeName, 600);
    recorder_.ExpectEntryMetric(entry, UserActivity::kScreenDimDelayName, 100);
    recorder_.ExpectEntryMetric(entry, UserActivity::kScreenDimmedInitiallyName,
                                false);
    recorder_.ExpectEntryMetric(entry, UserActivity::kScreenDimOccurredName,
                                true);
    recorder_.ExpectEntryMetric(entry, UserActivity::kScreenDimToOffDelayName,
                                200);
    recorder_.ExpectEntryMetric(entry, UserActivity::kScreenLockedInitiallyName,
                                false);
    recorder_.ExpectEntryMetric(entry, UserActivity::kScreenLockOccurredName,
                                true);
    recorder_.ExpectEntryMetric(entry, UserActivity::kScreenOffInitiallyName,
                                false);
    recorder_.ExpectEntryMetric(entry, UserActivity::kScreenOffOccurredName,
                                true);

    recorder_.ExpectEntryMetric(entry, UserActivity::kSequenceIdName, 1);
    EXPECT_FALSE(
        recorder_.EntryHasMetric(entry, UserActivity::kTimeSinceLastKeyName));
    recorder_.ExpectEntryMetric(entry, UserActivity::kTimeSinceLastMouseName,
                                100);
    recorder_.ExpectEntryMetric(entry, UserActivity::kTimeSinceLastTouchName,
                                311);
    recorder_.ExpectEntryMetric(
        entry, UserActivity::kTimeSinceLastVideoEndedName, 360);
    recorder_.ExpectEntryMetric(entry, UserActivity::kTouchEventsInLastHourName,
                                1000);
  }

  UserActivityEvent user_activity_event_;
  ukm::TestUkmRecorder recorder_;

 private:
  UserActivityUkmLoggerImpl user_activity_logger_delegate_ukm_;
};

TEST_F(UserActivityUkmLoggerTest, BasicLogging) {
  auto user_activity_event = user_activity_event_;
  UserActivityEvent::Features* features =
      user_activity_event.mutable_features();
  features->set_source_id(recorder_.GetNewSourceID());
  const GURL kUrl1 = GURL("https://example1.com/");
  features->set_tab_domain(kUrl1.host());
  features->set_engagement_score(90);
  features->set_has_form_entry(false);

  LogActivity(user_activity_event);

  const auto& activity_entries =
      recorder_.GetEntriesByName(UserActivity::kEntryName);
  EXPECT_EQ(1u, activity_entries.size());
  const ukm::mojom::UkmEntry* activity_entry = activity_entries[0];
  CheckUserActivityValues(activity_entry);

  const ukm::SourceId kSourceId = activity_entry->source_id;
  const auto& activity_id_entries =
      recorder_.GetEntriesByName(UserActivityId::kEntryName);
  EXPECT_EQ(1u, activity_id_entries.size());

  const ukm::mojom::UkmEntry* entry = activity_id_entries[0];
  recorder_.ExpectEntryMetric(entry, UserActivityId::kActivityIdName,
                              kSourceId);
  recorder_.ExpectEntryMetric(entry, UserActivityId::kSiteEngagementScoreName,
                              90);
  recorder_.ExpectEntryMetric(entry, UserActivityId::kHasFormEntryName, 0);
}

// Tests what would be logged in Incognito: when source IDs are not provided.
TEST_F(UserActivityUkmLoggerTest, EmptySources) {
  LogActivity(user_activity_event_);

  const auto& activity_entries =
      recorder_.GetEntriesByName(UserActivity::kEntryName);
  EXPECT_EQ(1u, activity_entries.size());
  const ukm::mojom::UkmEntry* activity_entry = activity_entries[0];

  CheckUserActivityValues(activity_entry);

  EXPECT_EQ(0u, recorder_.GetEntriesByName(UserActivityId::kEntryName).size());
}

TEST_F(UserActivityUkmLoggerTest, TwoUserActivityEvents) {
  // A second event will be logged. Values correspond with the checks below.
  UserActivityEvent user_activity_event2;
  UserActivityEvent::Event* event = user_activity_event2.mutable_event();
  event->set_log_duration_sec(35);
  event->set_reason(UserActivityEvent::Event::IDLE_SLEEP);
  event->set_type(UserActivityEvent::Event::TIMEOUT);

  UserActivityEvent::Features* features =
      user_activity_event2.mutable_features();
  features->set_battery_percent(86.0);
  features->set_device_management(UserActivityEvent::Features::MANAGED);
  features->set_device_mode(UserActivityEvent::Features::CLAMSHELL);
  features->set_device_type(UserActivityEvent::Features::CHROMEBOOK);
  features->set_last_activity_day(UserActivityEvent::Features::TUE);
  features->set_last_activity_time_sec(7300);
  features->set_last_user_activity_time_sec(3800);
  features->set_recent_time_active_sec(20);
  features->set_on_to_dim_sec(10);
  features->set_dim_to_screen_off_sec(20);
  features->set_time_since_last_mouse_sec(200);

  UserActivityEvent::ModelPrediction* prediction =
      user_activity_event2.mutable_model_prediction();
  prediction->set_model_applied(false);
  prediction->set_response(UserActivityEvent::ModelPrediction::MODEL_ERROR);

  LogActivity(user_activity_event_);
  LogActivity(user_activity_event2);

  const auto& activity_entries =
      recorder_.GetEntriesByName(UserActivity::kEntryName);
  EXPECT_EQ(2u, activity_entries.size());

  // Check the first user activity values.
  CheckUserActivityValues(activity_entries[0]);

  // Check the second user activity values.
  const ukm::mojom::UkmEntry* entry1 = activity_entries[1];
  recorder_.ExpectEntryMetric(entry1, UserActivity::kEventLogDurationName, 35);
  recorder_.ExpectEntryMetric(entry1, UserActivity::kEventReasonName,
                              UserActivityEvent::Event::IDLE_SLEEP);
  recorder_.ExpectEntryMetric(entry1, UserActivity::kEventTypeName,
                              UserActivityEvent::Event::TIMEOUT);
  recorder_.ExpectEntryMetric(entry1, UserActivity::kBatteryPercentName, 85);
  recorder_.ExpectEntryMetric(entry1, UserActivity::kDeviceManagementName,
                              UserActivityEvent::Features::MANAGED);
  recorder_.ExpectEntryMetric(entry1, UserActivity::kDeviceModeName,
                              UserActivityEvent::Features::CLAMSHELL);
  recorder_.ExpectEntryMetric(entry1, UserActivity::kDeviceTypeName,
                              UserActivityEvent::Features::CHROMEBOOK);
  recorder_.ExpectEntryMetric(entry1, UserActivity::kLastActivityDayName,
                              UserActivityEvent::Features::TUE);
  recorder_.ExpectEntryMetric(entry1, UserActivity::kLastActivityTimeName, 2);
  recorder_.ExpectEntryMetric(entry1, UserActivity::kLastUserActivityTimeName,
                              1);
  EXPECT_FALSE(recorder_.EntryHasMetric(entry1, UserActivity::kOnBatteryName));
  recorder_.ExpectEntryMetric(entry1, UserActivity::kRecentTimeActiveName, 20);
  recorder_.ExpectEntryMetric(entry1, UserActivity::kScreenDimDelayName, 10);
  recorder_.ExpectEntryMetric(entry1, UserActivity::kScreenDimToOffDelayName,
                              20);
  recorder_.ExpectEntryMetric(entry1, UserActivity::kSequenceIdName, 2);
  EXPECT_FALSE(
      recorder_.EntryHasMetric(entry1, UserActivity::kTimeSinceLastKeyName));
  recorder_.ExpectEntryMetric(entry1, UserActivity::kTimeSinceLastMouseName,
                              200);
  recorder_.ExpectEntryMetric(entry1, UserActivity::kModelResponseName, 2);
  recorder_.ExpectEntryMetric(entry1, UserActivity::kModelAppliedName, 0);
  EXPECT_FALSE(recorder_.EntryHasMetric(
      entry1, UserActivity::kModelDecisionThresholdName));
  EXPECT_FALSE(recorder_.EntryHasMetric(
      entry1, UserActivity::kModelInactivityScoreName));

  EXPECT_EQ(0u, recorder_.GetEntriesByName(UserActivityId::kEntryName).size());
}

}  // namespace ml
}  // namespace power
}  // namespace ash