| // Copyright 2017 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. |
| |
| #include "chrome/browser/media/media_engagement_score.h" |
| |
| #include <utility> |
| |
| #include "base/macros.h" |
| #include "base/metrics/field_trial_param_associator.h" |
| #include "base/metrics/field_trial_params.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/test/simple_test_clock.h" |
| #include "base/values.h" |
| #include "chrome/browser/content_settings/host_content_settings_map_factory.h" |
| #include "chrome/browser/engagement/site_engagement_service.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/test/base/chrome_render_view_host_test_harness.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "components/content_settings/core/browser/host_content_settings_map.h" |
| #include "media/base/media_switches.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "url/gurl.h" |
| |
| namespace { |
| |
| base::Time GetReferenceTime() { |
| base::Time::Exploded exploded_reference_time; |
| exploded_reference_time.year = 2015; |
| exploded_reference_time.month = 1; |
| exploded_reference_time.day_of_month = 30; |
| exploded_reference_time.day_of_week = 5; |
| exploded_reference_time.hour = 11; |
| exploded_reference_time.minute = 0; |
| exploded_reference_time.second = 0; |
| exploded_reference_time.millisecond = 0; |
| |
| base::Time out_time; |
| EXPECT_TRUE( |
| base::Time::FromLocalExploded(exploded_reference_time, &out_time)); |
| return out_time; |
| } |
| |
| } // namespace |
| |
| class MediaEngagementScoreTest : public ChromeRenderViewHostTestHarness { |
| public: |
| void SetUp() override { |
| ChromeRenderViewHostTestHarness::SetUp(); |
| test_clock.SetNow(GetReferenceTime()); |
| score_ = new MediaEngagementScore(&test_clock, GURL(), nullptr); |
| } |
| |
| void TearDown() override { |
| delete score_; |
| ChromeRenderViewHostTestHarness::TearDown(); |
| } |
| |
| base::SimpleTestClock test_clock; |
| |
| protected: |
| MediaEngagementScore* score_; |
| |
| void VerifyScore(MediaEngagementScore* score, |
| int expected_visits, |
| int expected_media_playbacks, |
| base::Time expected_last_media_playback_time, |
| bool has_high_score, |
| int audible_playbacks, |
| int significant_playbacks, |
| int visits_with_media_tag, |
| int high_score_changes, |
| int media_element_playbacks, |
| int audio_context_playbacks) { |
| EXPECT_EQ(expected_visits, score->visits()); |
| EXPECT_EQ(expected_media_playbacks, score->media_playbacks()); |
| EXPECT_EQ(expected_last_media_playback_time, |
| score->last_media_playback_time()); |
| EXPECT_EQ(has_high_score, score->high_score()); |
| EXPECT_EQ(audible_playbacks, score->audible_playbacks()); |
| EXPECT_EQ(significant_playbacks, score->significant_playbacks()); |
| EXPECT_EQ(visits_with_media_tag, score->visits_with_media_tag()); |
| EXPECT_EQ(high_score_changes, score->high_score_changes()); |
| EXPECT_EQ(media_element_playbacks, score->media_element_playbacks()); |
| EXPECT_EQ(audio_context_playbacks, score->audio_context_playbacks()); |
| } |
| |
| void UpdateScore(MediaEngagementScore* score) { |
| test_clock.SetNow(test_clock.Now() + base::TimeDelta::FromHours(1)); |
| |
| score->IncrementVisits(); |
| score->IncrementMediaPlaybacks(); |
| score->IncrementAudiblePlaybacks(1); |
| score->IncrementSignificantPlaybacks(1); |
| score->IncrementVisitsWithMediaTag(); |
| score->IncrementMediaElementPlaybacks(); |
| score->IncrementAudioContextPlaybacks(); |
| } |
| |
| void TestScoreInitializesAndUpdates( |
| std::unique_ptr<base::DictionaryValue> score_dict, |
| int expected_visits, |
| int expected_media_playbacks, |
| base::Time expected_last_media_playback_time, |
| bool has_high_score, |
| int audible_playbacks, |
| int significant_playbacks, |
| int visits_with_media_tag, |
| int high_score_changes, |
| int media_element_playbacks, |
| int audio_context_playbacks) { |
| MediaEngagementScore* initial_score = new MediaEngagementScore( |
| &test_clock, GURL(), std::move(score_dict), nullptr /* settings */); |
| VerifyScore(initial_score, expected_visits, expected_media_playbacks, |
| expected_last_media_playback_time, has_high_score, |
| audible_playbacks, significant_playbacks, visits_with_media_tag, |
| high_score_changes, media_element_playbacks, |
| audio_context_playbacks); |
| |
| // Updating the score dict should return false, as the score shouldn't |
| // have changed at this point. |
| EXPECT_FALSE(initial_score->UpdateScoreDict()); |
| |
| // Increment the scores and check that the values were stored correctly. |
| UpdateScore(initial_score); |
| EXPECT_TRUE(initial_score->UpdateScoreDict()); |
| delete initial_score; |
| } |
| |
| static void SetScore(MediaEngagementScore* score, |
| int visits, |
| int media_playbacks) { |
| score->SetVisits(visits); |
| score->SetMediaPlaybacks(media_playbacks); |
| } |
| |
| void SetScore(int visits, int media_playbacks) { |
| SetScore(score_, visits, media_playbacks); |
| } |
| |
| void VerifyGetScoreDetails(MediaEngagementScore* score) { |
| media::mojom::MediaEngagementScoreDetailsPtr details = |
| score->GetScoreDetails(); |
| EXPECT_EQ(details->origin, score->origin_); |
| EXPECT_EQ(details->total_score, score->actual_score()); |
| EXPECT_EQ(details->visits, score->visits()); |
| EXPECT_EQ(details->media_playbacks, score->media_playbacks()); |
| EXPECT_EQ(details->last_media_playback_time, |
| score->last_media_playback_time().ToJsTime()); |
| EXPECT_EQ(details->audible_playbacks, score->audible_playbacks()); |
| EXPECT_EQ(details->significant_playbacks, score->significant_playbacks()); |
| EXPECT_EQ(details->high_score_changes, score->high_score_changes()); |
| EXPECT_EQ(details->audio_context_playbacks, |
| score->audio_context_playbacks()); |
| EXPECT_EQ(details->media_element_playbacks, |
| score->media_element_playbacks()); |
| } |
| |
| void OverrideFieldTrial(int min_visits, |
| double lower_threshold, |
| double upper_threshold) { |
| field_trial_list_.reset(); |
| field_trial_list_ = std::make_unique<base::FieldTrialList>(nullptr); |
| base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting(); |
| |
| std::map<std::string, std::string> params; |
| params[MediaEngagementScore::kScoreMinVisitsParamName] = |
| std::to_string(min_visits); |
| params[MediaEngagementScore::kHighScoreLowerThresholdParamName] = |
| std::to_string(lower_threshold); |
| params[MediaEngagementScore::kHighScoreUpperThresholdParamName] = |
| std::to_string(upper_threshold); |
| |
| scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>(); |
| scoped_feature_list_->InitAndEnableFeatureWithParameters( |
| media::kMediaEngagementBypassAutoplayPolicies, params); |
| |
| std::map<std::string, std::string> actual_params; |
| EXPECT_TRUE(base::GetFieldTrialParamsByFeature( |
| media::kMediaEngagementBypassAutoplayPolicies, &actual_params)); |
| EXPECT_EQ(params, actual_params); |
| |
| score_->Recalculate(); |
| } |
| |
| private: |
| std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_; |
| std::unique_ptr<base::FieldTrialList> field_trial_list_; |
| }; |
| |
| // Test Mojo serialization. |
| TEST_F(MediaEngagementScoreTest, MojoSerialization) { |
| VerifyGetScoreDetails(score_); |
| UpdateScore(score_); |
| VerifyGetScoreDetails(score_); |
| } |
| |
| // Test that scores are read / written correctly from / to empty score |
| // dictionaries. |
| TEST_F(MediaEngagementScoreTest, EmptyDictionary) { |
| std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
| TestScoreInitializesAndUpdates(std::move(dict), 0, 0, base::Time(), false, 0, |
| 0, 0, 0, 0, 0); |
| } |
| |
| // Test that scores are read / written correctly from / to partially empty |
| // score dictionaries. |
| TEST_F(MediaEngagementScoreTest, PartiallyEmptyDictionary) { |
| std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
| dict->SetInteger(MediaEngagementScore::kVisitsKey, 2); |
| |
| TestScoreInitializesAndUpdates(std::move(dict), 2, 0, base::Time(), false, 0, |
| 0, 0, 0, 0, 0); |
| } |
| |
| // Test that scores are read / written correctly from / to populated score |
| // dictionaries. |
| TEST_F(MediaEngagementScoreTest, PopulatedDictionary) { |
| std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
| dict->SetInteger(MediaEngagementScore::kVisitsKey, 20); |
| dict->SetInteger(MediaEngagementScore::kMediaPlaybacksKey, 12); |
| dict->SetDouble(MediaEngagementScore::kLastMediaPlaybackTimeKey, |
| test_clock.Now().ToInternalValue()); |
| dict->SetBoolean(MediaEngagementScore::kHasHighScoreKey, true); |
| dict->SetInteger(MediaEngagementScore::kAudiblePlaybacksKey, 2); |
| dict->SetInteger(MediaEngagementScore::kSignificantPlaybacksKey, 4); |
| dict->SetInteger(MediaEngagementScore::kVisitsWithMediaTagKey, 6); |
| dict->SetInteger(MediaEngagementScore::kHighScoreChanges, 3); |
| dict->SetInteger(MediaEngagementScore::kSignificantMediaPlaybacksKey, 1); |
| dict->SetInteger(MediaEngagementScore::kSignificantAudioContextPlaybacksKey, |
| 2); |
| |
| TestScoreInitializesAndUpdates(std::move(dict), 20, 12, test_clock.Now(), |
| true, 2, 4, 6, 3, 1, 2); |
| } |
| |
| // Test getting and commiting the score works correctly with different |
| // origins. |
| TEST_F(MediaEngagementScoreTest, ContentSettingsMultiOrigin) { |
| GURL url("https://www.google.com"); |
| |
| // Replace |score_| with one with an actual URL, and with a settings map. |
| HostContentSettingsMap* settings_map = |
| HostContentSettingsMapFactory::GetForProfile(profile()); |
| MediaEngagementScore* score = |
| new MediaEngagementScore(&test_clock, url, settings_map); |
| |
| // Verify the score is originally zero, try incrementing and storing |
| // the score. |
| VerifyScore(score, 0, 0, base::Time(), false, 0, 0, 0, 0, 0, 0); |
| score->IncrementVisits(); |
| UpdateScore(score); |
| score->Commit(); |
| |
| // Now confirm the correct score is present on the same origin, |
| // but zero for a different origin. |
| GURL same_origin("https://www.google.com"); |
| GURL different_origin("https://www.google.co.uk"); |
| MediaEngagementScore* new_score = |
| new MediaEngagementScore(&test_clock, url, settings_map); |
| MediaEngagementScore* same_origin_score = |
| new MediaEngagementScore(&test_clock, same_origin, settings_map); |
| MediaEngagementScore* different_origin_score = |
| new MediaEngagementScore(&test_clock, different_origin, settings_map); |
| VerifyScore(new_score, 2, 1, test_clock.Now(), false, 1, 1, 1, 0, 1, 1); |
| VerifyScore(same_origin_score, 2, 1, test_clock.Now(), false, 1, 1, 1, 0, 1, |
| 1); |
| VerifyScore(different_origin_score, 0, 0, base::Time(), false, 0, 0, 0, 0, 0, |
| 0); |
| |
| delete score; |
| delete new_score; |
| delete same_origin_score; |
| delete different_origin_score; |
| } |
| |
| // Tests content settings read/write. |
| TEST_F(MediaEngagementScoreTest, ContentSettings) { |
| HostContentSettingsMap* settings_map = |
| HostContentSettingsMapFactory::GetForProfile(profile()); |
| int example_num_visits = 20; |
| int example_media_playbacks = 5; |
| int example_audible_playbacks = 3; |
| int example_significant_playbacks = 5; |
| int example_visits_with_media_tags = 20; |
| int example_high_score_changes = 1; |
| int example_media_element_playbacks = 1; |
| int example_audio_context_playbacks = 3; |
| |
| // Store some example data in content settings. |
| GURL origin("https://www.google.com"); |
| std::unique_ptr<base::DictionaryValue> score_dict = |
| std::make_unique<base::DictionaryValue>(); |
| score_dict->SetInteger(MediaEngagementScore::kVisitsKey, example_num_visits); |
| score_dict->SetInteger(MediaEngagementScore::kMediaPlaybacksKey, |
| example_media_playbacks); |
| score_dict->SetDouble(MediaEngagementScore::kLastMediaPlaybackTimeKey, |
| test_clock.Now().ToInternalValue()); |
| score_dict->SetBoolean(MediaEngagementScore::kHasHighScoreKey, false); |
| score_dict->SetInteger(MediaEngagementScore::kAudiblePlaybacksKey, |
| example_audible_playbacks); |
| score_dict->SetInteger(MediaEngagementScore::kSignificantPlaybacksKey, |
| example_significant_playbacks); |
| score_dict->SetInteger(MediaEngagementScore::kVisitsWithMediaTagKey, |
| example_visits_with_media_tags); |
| score_dict->SetInteger(MediaEngagementScore::kHighScoreChanges, |
| example_high_score_changes); |
| score_dict->SetInteger(MediaEngagementScore::kSignificantMediaPlaybacksKey, |
| example_media_element_playbacks); |
| score_dict->SetInteger( |
| MediaEngagementScore::kSignificantAudioContextPlaybacksKey, |
| example_audio_context_playbacks); |
| settings_map->SetWebsiteSettingDefaultScope( |
| origin, GURL(), CONTENT_SETTINGS_TYPE_MEDIA_ENGAGEMENT, |
| content_settings::ResourceIdentifier(), std::move(score_dict)); |
| |
| // Make sure we read that data back correctly. |
| MediaEngagementScore* score = |
| new MediaEngagementScore(&test_clock, origin, settings_map); |
| EXPECT_EQ(score->visits(), example_num_visits); |
| EXPECT_EQ(score->media_playbacks(), example_media_playbacks); |
| EXPECT_EQ(score->last_media_playback_time(), test_clock.Now()); |
| EXPECT_FALSE(score->high_score()); |
| EXPECT_EQ(score->audible_playbacks(), example_audible_playbacks); |
| EXPECT_EQ(score->significant_playbacks(), example_significant_playbacks); |
| EXPECT_EQ(score->visits_with_media_tag(), example_visits_with_media_tags); |
| EXPECT_EQ(score->visits_with_media_tag(), example_visits_with_media_tags); |
| EXPECT_EQ(score->high_score_changes(), example_high_score_changes); |
| EXPECT_EQ(score->media_element_playbacks(), example_media_element_playbacks); |
| EXPECT_EQ(score->audio_context_playbacks(), example_audio_context_playbacks); |
| |
| UpdateScore(score); |
| score->IncrementMediaPlaybacks(); |
| EXPECT_TRUE(score->high_score()); |
| score->Commit(); |
| |
| // Now read back content settings and make sure we have the right values. |
| int stored_visits; |
| int stored_media_playbacks; |
| double stored_last_media_playback_time; |
| bool stored_has_high_score; |
| int stored_audible_playbacks; |
| int stored_significant_playbacks; |
| int stored_visits_with_media_tag; |
| int stored_high_score_changes; |
| int stored_media_element_playbacks; |
| int stored_audio_context_playbacks; |
| std::unique_ptr<base::DictionaryValue> values = |
| base::DictionaryValue::From(settings_map->GetWebsiteSetting( |
| origin, GURL(), CONTENT_SETTINGS_TYPE_MEDIA_ENGAGEMENT, |
| content_settings::ResourceIdentifier(), nullptr)); |
| values->GetInteger(MediaEngagementScore::kVisitsKey, &stored_visits); |
| values->GetInteger(MediaEngagementScore::kMediaPlaybacksKey, |
| &stored_media_playbacks); |
| values->GetDouble(MediaEngagementScore::kLastMediaPlaybackTimeKey, |
| &stored_last_media_playback_time); |
| values->GetBoolean(MediaEngagementScore::kHasHighScoreKey, |
| &stored_has_high_score); |
| values->GetInteger(MediaEngagementScore::kAudiblePlaybacksKey, |
| &stored_audible_playbacks); |
| values->GetInteger(MediaEngagementScore::kSignificantPlaybacksKey, |
| &stored_significant_playbacks); |
| values->GetInteger(MediaEngagementScore::kVisitsWithMediaTagKey, |
| &stored_visits_with_media_tag); |
| values->GetInteger(MediaEngagementScore::kHighScoreChanges, |
| &stored_high_score_changes); |
| values->GetInteger(MediaEngagementScore::kSignificantMediaPlaybacksKey, |
| &stored_media_element_playbacks); |
| values->GetInteger(MediaEngagementScore::kSignificantAudioContextPlaybacksKey, |
| &stored_audio_context_playbacks); |
| EXPECT_EQ(stored_visits, example_num_visits + 1); |
| EXPECT_EQ(stored_media_playbacks, example_media_playbacks + 2); |
| EXPECT_EQ(stored_last_media_playback_time, |
| test_clock.Now().ToInternalValue()); |
| EXPECT_EQ(stored_audible_playbacks, example_audible_playbacks + 1); |
| EXPECT_EQ(stored_significant_playbacks, example_significant_playbacks + 1); |
| EXPECT_EQ(stored_visits_with_media_tag, example_visits_with_media_tags + 1); |
| EXPECT_TRUE(stored_has_high_score); |
| EXPECT_EQ(stored_high_score_changes, example_high_score_changes + 1); |
| EXPECT_EQ(stored_media_element_playbacks, |
| example_media_element_playbacks + 1); |
| EXPECT_EQ(stored_audio_context_playbacks, |
| example_audio_context_playbacks + 1); |
| |
| delete score; |
| } |
| |
| // Test that the engagement score is calculated correctly. |
| TEST_F(MediaEngagementScoreTest, EngagementScoreCalculation) { |
| EXPECT_EQ(0, score_->actual_score()); |
| UpdateScore(score_); |
| |
| // Check that the score increases when there is one visit. |
| EXPECT_EQ(0.05, score_->actual_score()); |
| |
| SetScore(20, 8); |
| EXPECT_EQ(0.4, score_->actual_score()); |
| |
| UpdateScore(score_); |
| EXPECT_EQ(9.0 / 21.0, score_->actual_score()); |
| } |
| |
| // Test that a score without the high_score bit uses the correct bounds. |
| TEST_F(MediaEngagementScoreTest, HighScoreLegacy_High) { |
| const GURL url("https://www.example.com"); |
| HostContentSettingsMap* settings_map = |
| HostContentSettingsMapFactory::GetForProfile(profile()); |
| |
| { |
| std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
| dict->SetInteger(MediaEngagementScore::kVisitsKey, 20); |
| dict->SetInteger(MediaEngagementScore::kMediaPlaybacksKey, 6); |
| settings_map->SetWebsiteSettingDefaultScope( |
| url, GURL(), CONTENT_SETTINGS_TYPE_MEDIA_ENGAGEMENT, |
| content_settings::ResourceIdentifier(), std::move(dict)); |
| } |
| |
| { |
| std::unique_ptr<MediaEngagementScore> score( |
| new MediaEngagementScore(&test_clock, url, settings_map)); |
| VerifyScore(score.get(), 20, 6, base::Time(), true, 0, 0, 0, 1, 6, 0); |
| } |
| } |
| |
| // Test that a score without the high_score bit uses the correct bounds. |
| TEST_F(MediaEngagementScoreTest, HighScoreLegacy_Low) { |
| const GURL url("https://www.example.com"); |
| HostContentSettingsMap* settings_map = |
| HostContentSettingsMapFactory::GetForProfile(profile()); |
| |
| { |
| std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
| dict->SetInteger(MediaEngagementScore::kVisitsKey, 20); |
| dict->SetInteger(MediaEngagementScore::kMediaPlaybacksKey, 4); |
| settings_map->SetWebsiteSettingDefaultScope( |
| url, GURL(), CONTENT_SETTINGS_TYPE_MEDIA_ENGAGEMENT, |
| content_settings::ResourceIdentifier(), std::move(dict)); |
| } |
| |
| { |
| std::unique_ptr<MediaEngagementScore> score( |
| new MediaEngagementScore(&test_clock, url, settings_map)); |
| VerifyScore(score.get(), 20, 4, base::Time(), false, 0, 0, 0, 0, 4, 0); |
| } |
| } |
| |
| // Test that if we changed the boundaries the high_score bit is updated |
| // when the score is loaded. |
| TEST_F(MediaEngagementScoreTest, HighScoreUpdated) { |
| const GURL url("https://www.example.com"); |
| HostContentSettingsMap* settings_map = |
| HostContentSettingsMapFactory::GetForProfile(profile()); |
| |
| { |
| std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
| dict->SetInteger(MediaEngagementScore::kVisitsKey, 10); |
| dict->SetInteger(MediaEngagementScore::kMediaPlaybacksKey, 1); |
| dict->SetDouble(MediaEngagementScore::kLastMediaPlaybackTimeKey, |
| test_clock.Now().ToInternalValue()); |
| dict->SetBoolean(MediaEngagementScore::kHasHighScoreKey, true); |
| |
| settings_map->SetWebsiteSettingDefaultScope( |
| url, GURL(), CONTENT_SETTINGS_TYPE_MEDIA_ENGAGEMENT, |
| content_settings::ResourceIdentifier(), std::move(dict)); |
| } |
| |
| { |
| std::unique_ptr<MediaEngagementScore> score( |
| new MediaEngagementScore(&test_clock, url, settings_map)); |
| EXPECT_FALSE(score->high_score()); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| { |
| std::unique_ptr<base::DictionaryValue> dict = |
| base::DictionaryValue::From(settings_map->GetWebsiteSetting( |
| url, GURL(), CONTENT_SETTINGS_TYPE_MEDIA_ENGAGEMENT, |
| content_settings::ResourceIdentifier(), nullptr)); |
| |
| bool stored_high_score = false; |
| dict->GetBoolean(MediaEngagementScore::kHasHighScoreKey, |
| &stored_high_score); |
| EXPECT_FALSE(stored_high_score); |
| } |
| } |
| |
| // Test that the has high score upper and lower thresholds work. |
| TEST_F(MediaEngagementScoreTest, HighScoreThreshold) { |
| EXPECT_FALSE(score_->high_score()); |
| |
| // Test that a total score of 0.1 is not high. |
| SetScore(20, 2); |
| EXPECT_FALSE(score_->high_score()); |
| |
| // Test that a total score of 0.25 is not high but above zero. |
| SetScore(20, 5); |
| EXPECT_FALSE(score_->high_score()); |
| |
| // Test that a total score of 0.3 is high. |
| SetScore(20, 6); |
| EXPECT_TRUE(score_->high_score()); |
| |
| // Test that a total score of 0.25 is high because of the lower boundary. |
| SetScore(20, 5); |
| EXPECT_TRUE(score_->high_score()); |
| |
| // Test that a total score of 0.1 is not high. |
| SetScore(20, 2); |
| EXPECT_FALSE(score_->high_score()); |
| } |
| |
| TEST_F(MediaEngagementScoreTest, OverrideFieldTrial) { |
| EXPECT_EQ(20, MediaEngagementScore::GetScoreMinVisits()); |
| EXPECT_EQ(0.2, MediaEngagementScore::GetHighScoreLowerThreshold()); |
| EXPECT_EQ(0.3, MediaEngagementScore::GetHighScoreUpperThreshold()); |
| |
| SetScore(20, 16); |
| EXPECT_EQ(0.8, score_->actual_score()); |
| EXPECT_TRUE(score_->high_score()); |
| |
| // Raise the upper threshold, since the score was already considered high we |
| // should still be high. |
| OverrideFieldTrial(5, 0.7, 0.9); |
| EXPECT_TRUE(score_->high_score()); |
| EXPECT_EQ(0.7, MediaEngagementScore::GetHighScoreLowerThreshold()); |
| EXPECT_EQ(0.9, MediaEngagementScore::GetHighScoreUpperThreshold()); |
| |
| // Raise the lower threshold, the score will no longer be high. |
| OverrideFieldTrial(5, 0.85, 0.9); |
| EXPECT_FALSE(score_->high_score()); |
| EXPECT_EQ(0.85, MediaEngagementScore::GetHighScoreLowerThreshold()); |
| |
| // Raise the minimum visits, the score will now be relative to this new |
| // visits requirements. |
| OverrideFieldTrial(25, 0.85, 0.9); |
| EXPECT_EQ(0.64, score_->actual_score()); |
| EXPECT_EQ(25, MediaEngagementScore::GetScoreMinVisits()); |
| } |
| |
| TEST_F(MediaEngagementScoreTest, HighScoreChanges) { |
| const GURL kUrl("https://www.example.com"); |
| HostContentSettingsMap* settings_map = |
| HostContentSettingsMapFactory::GetForProfile(profile()); |
| |
| { |
| std::unique_ptr<MediaEngagementScore> score( |
| new MediaEngagementScore(&test_clock, kUrl, settings_map)); |
| |
| EXPECT_EQ(0, score->high_score_changes()); |
| // Perfect score, high_score bit has changed. |
| SetScore(score.get(), 20, 20); |
| score->Commit(); |
| EXPECT_EQ(1, score->high_score_changes()); |
| } |
| |
| { |
| std::unique_ptr<MediaEngagementScore> score( |
| new MediaEngagementScore(&test_clock, kUrl, settings_map)); |
| |
| // Worse score, high_score bit has changed. |
| SetScore(score.get(), 20, 0); |
| score->Commit(); |
| EXPECT_EQ(2, score->high_score_changes()); |
| } |
| |
| // Bad score, high_score bit has not changed. |
| { |
| std::unique_ptr<MediaEngagementScore> score( |
| new MediaEngagementScore(&test_clock, kUrl, settings_map)); |
| |
| SetScore(score.get(), 20, 1); |
| score->Commit(); |
| EXPECT_EQ(2, score->high_score_changes()); |
| } |
| } |
| |
| // Test that we migrate the media playbacks value to media element playbacks. |
| TEST_F(MediaEngagementScoreTest, MigrateMediaElementPlaybacks) { |
| const GURL url("https://www.example.com"); |
| HostContentSettingsMap* settings_map = |
| HostContentSettingsMapFactory::GetForProfile(profile()); |
| int media_playbacks = 6; |
| |
| { |
| std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
| dict->SetBoolean(MediaEngagementScore::kHasHighScoreKey, true); |
| dict->SetInteger(MediaEngagementScore::kMediaPlaybacksKey, media_playbacks); |
| |
| settings_map->SetWebsiteSettingDefaultScope( |
| url, GURL(), CONTENT_SETTINGS_TYPE_MEDIA_ENGAGEMENT, |
| content_settings::ResourceIdentifier(), std::move(dict)); |
| } |
| |
| { |
| std::unique_ptr<MediaEngagementScore> score( |
| new MediaEngagementScore(&test_clock, url, settings_map)); |
| EXPECT_EQ(media_playbacks, score->media_playbacks()); |
| EXPECT_EQ(media_playbacks, score->media_element_playbacks()); |
| |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| { |
| std::unique_ptr<base::DictionaryValue> dict = |
| base::DictionaryValue::From(settings_map->GetWebsiteSetting( |
| url, GURL(), CONTENT_SETTINGS_TYPE_MEDIA_ENGAGEMENT, |
| content_settings::ResourceIdentifier(), nullptr)); |
| |
| int stored_media_playbacks = 0; |
| int stored_media_element_playbacks = 0; |
| |
| dict->GetInteger(MediaEngagementScore::kMediaPlaybacksKey, |
| &stored_media_playbacks); |
| dict->GetInteger(MediaEngagementScore::kSignificantMediaPlaybacksKey, |
| &stored_media_element_playbacks); |
| |
| EXPECT_EQ(media_playbacks, stored_media_playbacks); |
| EXPECT_EQ(media_playbacks, stored_media_element_playbacks); |
| } |
| } |
| |
| // Test that we do not migrate media element playbacks if we have an audio |
| // context playback. |
| TEST_F(MediaEngagementScoreTest, |
| NoMigrateMediaElementPlaybacks_AudioContextPresent) { |
| const GURL url("https://www.example.com"); |
| HostContentSettingsMap* settings_map = |
| HostContentSettingsMapFactory::GetForProfile(profile()); |
| int media_playbacks = 6; |
| int audio_context_playbacks = 3; |
| |
| { |
| std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
| dict->SetBoolean(MediaEngagementScore::kHasHighScoreKey, true); |
| dict->SetInteger(MediaEngagementScore::kMediaPlaybacksKey, media_playbacks); |
| dict->SetInteger(MediaEngagementScore::kSignificantAudioContextPlaybacksKey, |
| audio_context_playbacks); |
| |
| settings_map->SetWebsiteSettingDefaultScope( |
| url, GURL(), CONTENT_SETTINGS_TYPE_MEDIA_ENGAGEMENT, |
| content_settings::ResourceIdentifier(), std::move(dict)); |
| } |
| |
| { |
| std::unique_ptr<MediaEngagementScore> score( |
| new MediaEngagementScore(&test_clock, url, settings_map)); |
| EXPECT_EQ(media_playbacks, score->media_playbacks()); |
| EXPECT_EQ(0, score->media_element_playbacks()); |
| EXPECT_EQ(audio_context_playbacks, score->audio_context_playbacks()); |
| |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| { |
| std::unique_ptr<base::DictionaryValue> dict = |
| base::DictionaryValue::From(settings_map->GetWebsiteSetting( |
| url, GURL(), CONTENT_SETTINGS_TYPE_MEDIA_ENGAGEMENT, |
| content_settings::ResourceIdentifier(), nullptr)); |
| |
| EXPECT_NE(nullptr, dict->FindKey(MediaEngagementScore::kMediaPlaybacksKey)); |
| EXPECT_EQ( |
| nullptr, |
| dict->FindKey(MediaEngagementScore::kSignificantMediaPlaybacksKey)); |
| } |
| } |
| |
| // Test that we do not migrate media element playbacks if we have a media |
| // element playback. |
| TEST_F(MediaEngagementScoreTest, |
| NoMigrateMediaElementPlaybacks_MediaElementPresent) { |
| const GURL url("https://www.example.com"); |
| HostContentSettingsMap* settings_map = |
| HostContentSettingsMapFactory::GetForProfile(profile()); |
| int media_playbacks = 6; |
| int media_element_playbacks = 3; |
| |
| { |
| std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
| dict->SetBoolean(MediaEngagementScore::kHasHighScoreKey, true); |
| dict->SetInteger(MediaEngagementScore::kMediaPlaybacksKey, media_playbacks); |
| dict->SetInteger(MediaEngagementScore::kSignificantMediaPlaybacksKey, |
| media_element_playbacks); |
| |
| settings_map->SetWebsiteSettingDefaultScope( |
| url, GURL(), CONTENT_SETTINGS_TYPE_MEDIA_ENGAGEMENT, |
| content_settings::ResourceIdentifier(), std::move(dict)); |
| } |
| |
| { |
| std::unique_ptr<MediaEngagementScore> score( |
| new MediaEngagementScore(&test_clock, url, settings_map)); |
| EXPECT_EQ(media_playbacks, score->media_playbacks()); |
| EXPECT_EQ(media_element_playbacks, score->media_element_playbacks()); |
| |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| { |
| std::unique_ptr<base::DictionaryValue> dict = |
| base::DictionaryValue::From(settings_map->GetWebsiteSetting( |
| url, GURL(), CONTENT_SETTINGS_TYPE_MEDIA_ENGAGEMENT, |
| content_settings::ResourceIdentifier(), nullptr)); |
| |
| int stored_media_playbacks = 0; |
| int stored_media_element_playbacks = 0; |
| |
| dict->GetInteger(MediaEngagementScore::kMediaPlaybacksKey, |
| &stored_media_playbacks); |
| dict->GetInteger(MediaEngagementScore::kSignificantMediaPlaybacksKey, |
| &stored_media_element_playbacks); |
| |
| EXPECT_EQ(media_playbacks, stored_media_playbacks); |
| EXPECT_EQ(media_element_playbacks, stored_media_element_playbacks); |
| } |
| } |