| // Copyright 2018 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 "components/ntp_snippets/contextual/reporting/contextual_suggestions_metrics_reporter.h" |
| |
| #include "base/macros.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/scoped_task_environment.h" |
| #include "components/ntp_snippets/contextual/reporting/contextual_suggestions_ukm_entry.h" |
| #include "components/ukm/test_ukm_recorder.h" |
| #include "services/metrics/public/cpp/ukm_builders.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "url/gurl.h" |
| |
| using ukm::TestUkmRecorder; |
| using ukm::builders::ContextualSuggestions; |
| |
| namespace contextual_suggestions { |
| |
| namespace { |
| const char kEventsHistogramName[] = "ContextualSuggestions.Events"; |
| const char kTestNavigationUrl[] = "https://foo.com"; |
| const int kUninitialized = 0; |
| const int kFetchDelayed = 1; |
| const int kFetchRequested = 2; |
| const int kFetchError = 3; |
| const int kFetchServerBusy = 4; |
| const int kFetchBelowThreshold = 5; |
| const int kFetchEmpty = 6; |
| const int kFetchCompleted = 7; |
| const int kUiPeekReverseScroll = 8; |
| const int kUiOpened = 9; |
| const int kUiClosedObsolete = 10; |
| const int kSuggestionDownloaded = 11; |
| const int kSuggestionClicked = 12; |
| const int kUiDismissedWithoutOpen = 13; |
| const int kUiDismissedAfterOpen = 14; |
| const int kUiButtonShown = 15; |
| } // namespace |
| |
| class ContextualSuggestionsMetricsReporterTest : public ::testing::Test { |
| protected: |
| ContextualSuggestionsMetricsReporterTest() = default; |
| |
| TestUkmRecorder* GetTestUkmRecorder() { return &test_ukm_recorder_; } |
| |
| ukm::SourceId GetSourceId(); |
| |
| ContextualSuggestionsMetricsReporter& GetReporter() { return reporter_; } |
| |
| protected: |
| void ExpectMultipleEventsCountOnce(ContextualSuggestionsEvent event); |
| |
| private: |
| // The reporter under test. |
| ContextualSuggestionsMetricsReporter reporter_; |
| |
| // Sets up the task scheduling/task-runner environment for each test. |
| base::test::ScopedTaskEnvironment scoped_task_environment_; |
| |
| // Sets itself as the global UkmRecorder on construction. |
| ukm::TestAutoSetUkmRecorder test_ukm_recorder_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ContextualSuggestionsMetricsReporterTest); |
| }; |
| |
| ukm::SourceId ContextualSuggestionsMetricsReporterTest::GetSourceId() { |
| ukm::SourceId source_id = ukm::UkmRecorder::GetNewSourceID(); |
| test_ukm_recorder_.UpdateSourceURL(source_id, GURL(kTestNavigationUrl)); |
| return source_id; |
| } |
| |
| TEST_F(ContextualSuggestionsMetricsReporterTest, BaseTest) { |
| base::HistogramTester histogram_tester; |
| GetReporter().SetupForPage(kTestNavigationUrl, GetSourceId()); |
| GetReporter().RecordEvent(FETCH_REQUESTED); |
| GetReporter().RecordEvent(FETCH_COMPLETED); |
| GetReporter().RecordEvent(UI_PEEK_REVERSE_SCROLL); |
| GetReporter().RecordEvent(UI_OPENED); |
| GetReporter().RecordEvent(SUGGESTION_DOWNLOADED); |
| GetReporter().RecordEvent(SUGGESTION_CLICKED); |
| // Flush data to write to UKM. |
| GetReporter().Flush(); |
| // Check that we wrote something to UKM. Details of UKM reporting are tested |
| // in a different test suite. |
| TestUkmRecorder* test_ukm_recorder = GetTestUkmRecorder(); |
| std::vector<const ukm::mojom::UkmEntry*> entry_vector = |
| test_ukm_recorder->GetEntriesByName(ContextualSuggestions::kEntryName); |
| EXPECT_EQ(1U, entry_vector.size()); |
| const ukm::mojom::UkmEntry* first_entry = entry_vector[0]; |
| EXPECT_TRUE(test_ukm_recorder->EntryHasMetric( |
| first_entry, ContextualSuggestions::kFetchStateName)); |
| EXPECT_EQ(static_cast<int64_t>(FetchState::COMPLETED), |
| *(test_ukm_recorder->GetEntryMetric( |
| first_entry, ContextualSuggestions::kFetchStateName))); |
| // Test that the expected histogram events were written. |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kUninitialized, 0); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kFetchDelayed, 0); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kFetchRequested, 1); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kFetchError, 0); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kFetchServerBusy, 0); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kFetchBelowThreshold, |
| 0); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kFetchEmpty, 0); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kFetchCompleted, 1); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kUiPeekReverseScroll, |
| 1); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kUiOpened, 1); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kUiClosedObsolete, |
| 0); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, |
| kSuggestionDownloaded, 1); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kSuggestionClicked, |
| 1); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, |
| kUiDismissedWithoutOpen, 0); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, |
| kUiDismissedAfterOpen, 0); |
| } |
| |
| void ContextualSuggestionsMetricsReporterTest::ExpectMultipleEventsCountOnce( |
| ContextualSuggestionsEvent event) { |
| std::unique_ptr<base::HistogramTester> histogram_tester = |
| std::make_unique<base::HistogramTester>(); |
| GetReporter().SetupForPage(kTestNavigationUrl, GetSourceId()); |
| // Always report a single FETCH_DELAYED event so we ensure there's a |
| // histogram (otherwise the ExpectBucketCount may crash). |
| GetReporter().RecordEvent(FETCH_DELAYED); |
| int event_index = static_cast<int>(event); |
| histogram_tester->ExpectBucketCount(kEventsHistogramName, event_index, 0); |
| // Peek the UI, which starts the timer, expected by all the other UI or |
| // suggestion events. |
| GetReporter().RecordEvent(UI_PEEK_REVERSE_SCROLL); |
| // Report the event that we want to test multiple times. |
| GetReporter().RecordEvent(event); |
| GetReporter().RecordEvent(event); |
| histogram_tester->ExpectBucketCount(kEventsHistogramName, event_index, 1); |
| GetReporter().Flush(); |
| } |
| |
| TEST_F(ContextualSuggestionsMetricsReporterTest, UiPeekReverseScrollTest) { |
| ExpectMultipleEventsCountOnce(UI_PEEK_REVERSE_SCROLL); |
| } |
| |
| TEST_F(ContextualSuggestionsMetricsReporterTest, UiOpenedTest) { |
| ExpectMultipleEventsCountOnce(UI_OPENED); |
| } |
| |
| TEST_F(ContextualSuggestionsMetricsReporterTest, UiDismissedWithoutOpenTest) { |
| ExpectMultipleEventsCountOnce(UI_DISMISSED_WITHOUT_OPEN); |
| } |
| |
| TEST_F(ContextualSuggestionsMetricsReporterTest, UiDismissedAfterOpenTest) { |
| ExpectMultipleEventsCountOnce(UI_DISMISSED_AFTER_OPEN); |
| } |
| |
| TEST_F(ContextualSuggestionsMetricsReporterTest, SuggestionDownloadedTest) { |
| ExpectMultipleEventsCountOnce(SUGGESTION_DOWNLOADED); |
| } |
| |
| TEST_F(ContextualSuggestionsMetricsReporterTest, SuggestionClickedTest) { |
| ExpectMultipleEventsCountOnce(SUGGESTION_CLICKED); |
| } |
| |
| TEST_F(ContextualSuggestionsMetricsReporterTest, MultipleEventsTest) { |
| std::unique_ptr<base::HistogramTester> histogram_tester = |
| std::make_unique<base::HistogramTester>(); |
| GetReporter().SetupForPage(kTestNavigationUrl, GetSourceId()); |
| // Test multiple cycles of FETCH_REQUESTED, FETCH_COMPLETED. |
| GetReporter().RecordEvent(FETCH_REQUESTED); |
| histogram_tester->ExpectBucketCount(kEventsHistogramName, kFetchRequested, 1); |
| histogram_tester->ExpectBucketCount(kEventsHistogramName, kFetchCompleted, 0); |
| GetReporter().RecordEvent(FETCH_COMPLETED); |
| histogram_tester->ExpectBucketCount(kEventsHistogramName, kFetchRequested, 1); |
| histogram_tester->ExpectBucketCount(kEventsHistogramName, kFetchCompleted, 1); |
| GetReporter().RecordEvent(FETCH_REQUESTED); |
| histogram_tester->ExpectBucketCount(kEventsHistogramName, kFetchRequested, 2); |
| histogram_tester->ExpectBucketCount(kEventsHistogramName, kFetchCompleted, 1); |
| GetReporter().RecordEvent(FETCH_COMPLETED); |
| histogram_tester->ExpectBucketCount(kEventsHistogramName, kFetchRequested, 2); |
| histogram_tester->ExpectBucketCount(kEventsHistogramName, kFetchCompleted, 2); |
| GetReporter().Flush(); |
| } |
| |
| // Test that might catch enum reordering that's not done right. |
| TEST_F(ContextualSuggestionsMetricsReporterTest, EnumNotReorderedTest) { |
| std::unique_ptr<base::HistogramTester> histogram_tester = |
| std::make_unique<base::HistogramTester>(); |
| GetReporter().SetupForPage(kTestNavigationUrl, GetSourceId()); |
| // Peek the UI, which starts the timer, expected by all the other UI or |
| // suggestion events. |
| GetReporter().RecordEvent(UI_PEEK_REVERSE_SCROLL); |
| // The current last legal event. |
| GetReporter().RecordEvent(SUGGESTION_CLICKED); |
| histogram_tester->ExpectBucketCount(kEventsHistogramName, kSuggestionClicked, |
| 1); |
| GetReporter().Flush(); |
| } |
| |
| TEST_F(ContextualSuggestionsMetricsReporterTest, ButtonTest) { |
| base::HistogramTester histogram_tester; |
| GetReporter().SetupForPage(kTestNavigationUrl, GetSourceId()); |
| GetReporter().RecordEvent(FETCH_REQUESTED); |
| GetReporter().RecordEvent(FETCH_COMPLETED); |
| GetReporter().RecordEvent(UI_BUTTON_SHOWN); |
| GetReporter().RecordEvent(UI_OPENED); |
| GetReporter().RecordEvent(SUGGESTION_DOWNLOADED); |
| GetReporter().RecordEvent(SUGGESTION_CLICKED); |
| // Flush data to write to UKM. |
| GetReporter().Flush(); |
| // Check that we wrote something to UKM. Details of UKM reporting are tested |
| // in a different test suite. |
| TestUkmRecorder* test_ukm_recorder = GetTestUkmRecorder(); |
| std::vector<const ukm::mojom::UkmEntry*> entry_vector = |
| test_ukm_recorder->GetEntriesByName(ContextualSuggestions::kEntryName); |
| EXPECT_EQ(1U, entry_vector.size()); |
| const ukm::mojom::UkmEntry* first_entry = entry_vector[0]; |
| EXPECT_TRUE(test_ukm_recorder->EntryHasMetric( |
| first_entry, ContextualSuggestions::kFetchStateName)); |
| EXPECT_EQ(static_cast<int64_t>(FetchState::COMPLETED), |
| *(test_ukm_recorder->GetEntryMetric( |
| first_entry, ContextualSuggestions::kFetchStateName))); |
| // Test that the expected histogram events were written. |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kUninitialized, 0); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kFetchDelayed, 0); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kFetchRequested, 1); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kFetchError, 0); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kFetchServerBusy, 0); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kFetchBelowThreshold, |
| 0); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kFetchEmpty, 0); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kFetchCompleted, 1); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kUiButtonShown, 1); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kUiOpened, 1); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kUiClosedObsolete, |
| 0); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, |
| kSuggestionDownloaded, 1); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, kSuggestionClicked, |
| 1); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, |
| kUiDismissedWithoutOpen, 0); |
| histogram_tester.ExpectBucketCount(kEventsHistogramName, |
| kUiDismissedAfterOpen, 0); |
| } |
| |
| } // namespace contextual_suggestions |