| // Copyright 2025 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/contextual_search/contextual_search_metrics_recorder.h" |
| |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/task_environment.h" |
| #include "base/unguessable_token.h" |
| #include "components/lens/lens_overlay_mime_type.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace contextual_search { |
| |
| namespace { |
| const char kContextualSearchSourceUnknownSuffix[] = ".Unknown"; |
| const char kContextualSearchFileDeleted[] = |
| "ContextualSearch.Session.File.DeletedCount"; |
| const char kContextualSearchSessionDurationTotal[] = |
| "ContextualSearch.Session.Duration.Total.Unknown"; |
| const char kContextualSearchSessionAbandonedDuration[] = |
| "ContextualSearch.Session.Duration.Abandoned.Unknown"; |
| const char kContextualSearchSessionDurationQuerySubmitted[] = |
| "ContextualSearch.Session.Duration.QuerySubmitted.Unknown"; |
| const char kContextualSearchQuerySubmissionTime[] = |
| "ContextualSearch.Query.Time.ToSubmission.Unknown"; |
| const char kContextualSearchFileUploadAttemptPdf[] = |
| "ContextualSearch.Session.File.Browser.UploadAttemptCount.Pdf.Unknown"; |
| const char kContextualSearchFileUploadSuccessPdf[] = |
| "ContextualSearch.Session.File.Browser.UploadSuccessCount.Pdf.Unknown"; |
| const char kContextualSearchFileUploadSuccessAll[] = |
| "ContextualSearch.Session.File.Browser.UploadSuccessCount.Unknown"; |
| const char kContextualSearchFileUploadServerErrorPdf[] = |
| "ContextualSearch.Session.File.Browser.UploadFailureCount.Pdf.Unknown"; |
| const char kContextualSearchFileValidationBrowserErrorForPdf[] = |
| "ContextualSearch.Session.File.Browser.ValidationFailureCount.Pdf." |
| "BrowserProcessingError.Unknown"; |
| const char kContextualSearchFileValidationBrowserErrorAll[] = |
| "ContextualSearch.Session.File.Browser.ValidationFailureCount." |
| "BrowserProcessingError.Unknown"; |
| const char kContextualSearchFileUploadAttemptAll[] = |
| "ContextualSearch.Session.File.Browser.UploadAttemptCount.Unknown"; |
| const char kContextualSearchFileUploadAttempt[] = |
| "ContextualSearch.Session.File.Browser.UploadAttemptCount."; |
| const char kContextualSearchFileUploadSuccess[] = |
| "ContextualSearch.Session.File.Browser.UploadSuccessCount."; |
| const char kContextualSearchFileUploadFailure[] = |
| "ContextualSearch.Session.File.Browser.UploadFailureCount."; |
| const char kContextualSearchFileUploadFailureAll[] = |
| "ContextualSearch.Session.File.Browser.UploadFailureCount.Unknown"; |
| const char kContextualSearchFileValidationErrorTypes[] = |
| "ContextualSearch.Session.File.Browser.ValidationFailureCount."; |
| const char kContextualSearchQueryTextLength[] = |
| "ContextualSearch.Query.TextLength.Unknown"; |
| const char kContextualSearchQueryFileCount[] = |
| "ContextualSearch.Query.FileCount.Unknown"; |
| const char kContextualSearchQueryModality[] = |
| "ContextualSearch.Query.Modality.V2.Unknown"; |
| const char kContextualSearchQueryCount[] = |
| "ContextualSearch.Session.QueryCount.Unknown"; |
| const char kContextualSearchFileSizePdf[] = |
| "ContextualSearch.File.Size.Pdf.Unknown"; |
| const char kContextualSearchFileSizeAll[] = |
| "ContextualSearch.File.Size.Unknown"; |
| const char kContextualSearchFileSizeImage[] = |
| "ContextualSearch.File.Size.Image.Unknown"; |
| const char kContextualSearchToolsSubmissionType[] = |
| "ContextualSearch.Tools.SubmissionType.Unknown"; |
| const char kContextualSearchDeepSearchToolState[] = |
| "ContextualSearch.Tools.DeepSearch.Unknown"; |
| const char kContextualSearchTabContextAdded[] = |
| "ContextualSearch.TabContextAdded.V2.Unknown"; |
| const char kContextualSearchTabContextAddedFromSuggestionChip[] = |
| "ContextualSearch.TabContextAddedFromTabSuggestionChip.Unknown"; |
| const char kContextualSearchTabContextAddedFromPlusButton[] = |
| "ContextualSearch.TabContextAddedFromPlusButton.Unknown"; |
| const char kContextualSearchTabWithDuplicateTitleClicked[] = |
| "ContextualSearch.TabWithDuplicateTitleClicked.V2.Unknown"; |
| |
| std::string UploadStatusToString(FileUploadStatus status) { |
| switch (status) { |
| case FileUploadStatus::kNotUploaded: |
| return "NotUploaded"; |
| case FileUploadStatus::kProcessing: |
| return "Processing"; |
| case FileUploadStatus::kValidationFailed: |
| return "ValidationFailed"; |
| case FileUploadStatus::kUploadStarted: |
| return "UploadStarted"; |
| case FileUploadStatus::kUploadSuccessful: |
| return "UploadSuccessful"; |
| case FileUploadStatus::kUploadFailed: |
| return "UploadFailed"; |
| default: |
| return "Unknown"; |
| } |
| } |
| } // namespace |
| |
| class ContextualSearchMetricsRecorderTest : public testing::Test { |
| public: |
| ContextualSearchMetricsRecorderTest() = default; |
| ~ContextualSearchMetricsRecorderTest() override = default; |
| |
| void SetUp() override { CreateMetricsRecorder(); } |
| |
| void CreateMetricsRecorder() { |
| metrics_recorder_ = std::make_unique<ContextualSearchMetricsRecorder>( |
| ContextualSearchSource::kUnknown); |
| } |
| |
| ContextualSearchMetricsRecorder& metrics() { return *metrics_recorder_; } |
| base::HistogramTester& histogram_tester() { return histogram_tester_; } |
| base::test::TaskEnvironment& task_environment() { return task_environment_; } |
| |
| void DestructMetricsRecorder() { metrics_recorder_.reset(); } |
| |
| private: |
| std::unique_ptr<ContextualSearchMetricsRecorder> metrics_recorder_; |
| base::HistogramTester histogram_tester_; |
| base::test::TaskEnvironment task_environment_{ |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME}; |
| }; |
| |
| TEST_F(ContextualSearchMetricsRecorderTest, SessionAbandoned) { |
| // Setup user flow. |
| metrics().NotifySessionStateChanged(SessionState::kSessionStarted); |
| task_environment().FastForwardBy(base::Seconds(60)); |
| metrics().NotifySessionStateChanged(SessionState::kSessionAbandoned); |
| |
| histogram_tester().ExpectTotalCount(kContextualSearchSessionAbandonedDuration, |
| 1); |
| histogram_tester().ExpectTotalCount(kContextualSearchSessionDurationTotal, 1); |
| // Check session duration times. |
| histogram_tester().ExpectUniqueTimeSample( |
| kContextualSearchSessionAbandonedDuration, base::Seconds(60), 1); |
| histogram_tester().ExpectUniqueTimeSample( |
| kContextualSearchSessionDurationTotal, base::Seconds(60), 1); |
| } |
| |
| TEST_F(ContextualSearchMetricsRecorderTest, SessionCompleted) { |
| // Setup user flow. |
| metrics().NotifySessionStateChanged(SessionState::kSessionStarted); |
| task_environment().FastForwardBy(base::Seconds(10)); |
| metrics().NotifySessionStateChanged(SessionState::kQuerySubmitted); |
| metrics().NotifySessionStateChanged(SessionState::kNavigationOccurred); |
| |
| DestructMetricsRecorder(); |
| histogram_tester().ExpectTotalCount( |
| kContextualSearchSessionDurationQuerySubmitted, 1); |
| histogram_tester().ExpectTotalCount(kContextualSearchSessionDurationTotal, 1); |
| histogram_tester().ExpectTotalCount(kContextualSearchQuerySubmissionTime, 1); |
| // Check session duration times. |
| histogram_tester().ExpectUniqueTimeSample( |
| kContextualSearchSessionDurationQuerySubmitted, base::Seconds(10), 1); |
| histogram_tester().ExpectUniqueTimeSample( |
| kContextualSearchSessionDurationTotal, base::Seconds(10), 1); |
| // Check query submission time. |
| histogram_tester().ExpectUniqueTimeSample( |
| kContextualSearchQuerySubmissionTime, base::Seconds(10), 1); |
| } |
| |
| TEST_F(ContextualSearchMetricsRecorderTest, MultiQuerySubmissionSession) { |
| // Setup user flow. |
| metrics().NotifySessionStateChanged(SessionState::kSessionStarted); |
| task_environment().FastForwardBy(base::Seconds(30)); |
| metrics().NotifySessionStateChanged(SessionState::kQuerySubmitted); |
| metrics().RecordQueryMetrics(/*text_length=*/100, /*file_count=*/1); |
| metrics().NotifySessionStateChanged(SessionState::kNavigationOccurred); |
| |
| // Mimic the session remaining open when the AIM page is opened in another |
| // tab/window. In this case more queries can be submitted. |
| task_environment().FastForwardBy(base::Seconds(60)); |
| metrics().NotifySessionStateChanged(SessionState::kQuerySubmitted); |
| metrics().NotifySessionStateChanged(SessionState::kNavigationOccurred); |
| |
| metrics().NotifySessionStateChanged(SessionState::kSessionAbandoned); |
| histogram_tester().ExpectTotalCount( |
| kContextualSearchSessionDurationQuerySubmitted, 1); |
| histogram_tester().ExpectTotalCount(kContextualSearchSessionDurationTotal, 1); |
| histogram_tester().ExpectTotalCount(kContextualSearchQuerySubmissionTime, 2); |
| // Check session duration times. |
| histogram_tester().ExpectUniqueTimeSample( |
| kContextualSearchSessionDurationQuerySubmitted, base::Seconds(90), 1); |
| histogram_tester().ExpectUniqueTimeSample( |
| kContextualSearchSessionDurationTotal, base::Seconds(90), 1); |
| // Check query submission times. |
| histogram_tester().ExpectTimeBucketCount(kContextualSearchQuerySubmissionTime, |
| base::Seconds(30), 1); |
| histogram_tester().ExpectTimeBucketCount(kContextualSearchQuerySubmissionTime, |
| base::Seconds(90), 1); |
| histogram_tester().ExpectBucketCount(kContextualSearchQueryFileCount, 1, 1); |
| histogram_tester().ExpectBucketCount(kContextualSearchQueryCount, 2, 1); |
| } |
| |
| TEST_F(ContextualSearchMetricsRecorderTest, TextOnlyQuerySubmissionSession) { |
| // Setup user flow. |
| metrics().NotifySessionStateChanged(SessionState::kSessionStarted); |
| int text_length = 1000; |
| int file_count = 0; |
| metrics().RecordQueryMetrics(text_length, file_count); |
| |
| histogram_tester().ExpectBucketCount(kContextualSearchQueryTextLength, |
| text_length, 1); |
| histogram_tester().ExpectBucketCount( |
| kContextualSearchQueryModality, |
| ContextualSearchMultimodalState::kTextOnly, 1); |
| histogram_tester().ExpectBucketCount(kContextualSearchQueryFileCount, |
| file_count, 1); |
| } |
| |
| TEST_F(ContextualSearchMetricsRecorderTest, FileOnlyQuerySubmissionSession) { |
| // Setup user flow. |
| metrics().NotifySessionStateChanged(SessionState::kSessionStarted); |
| int text_length = 0; |
| int file_count = 2; |
| metrics().RecordQueryMetrics(text_length, file_count); |
| |
| histogram_tester().ExpectBucketCount(kContextualSearchQueryTextLength, |
| text_length, 1); |
| histogram_tester().ExpectBucketCount( |
| kContextualSearchQueryModality, |
| ContextualSearchMultimodalState::kFileOnly, 1); |
| histogram_tester().ExpectBucketCount(kContextualSearchQueryFileCount, |
| file_count, 1); |
| } |
| |
| TEST_F(ContextualSearchMetricsRecorderTest, MultimodalQuerySubmissionSession) { |
| // Setup user flow. |
| metrics().NotifySessionStateChanged(SessionState::kSessionStarted); |
| int text_length = 1000; |
| int file_count = 1; |
| metrics().RecordQueryMetrics(text_length, file_count); |
| |
| histogram_tester().ExpectBucketCount(kContextualSearchQueryTextLength, |
| text_length, 1); |
| histogram_tester().ExpectBucketCount( |
| kContextualSearchQueryModality, |
| ContextualSearchMultimodalState::kTextAndFile, 1); |
| histogram_tester().ExpectBucketCount(kContextualSearchQueryFileCount, |
| file_count, 1); |
| } |
| |
| TEST_F(ContextualSearchMetricsRecorderTest, ToolsSubmissionType) { |
| // Setup user flow. |
| metrics().NotifySessionStateChanged(SessionState::kSessionStarted); |
| metrics().RecordToolsSubmissionType(SubmissionType::kDeepSearch); |
| |
| histogram_tester().ExpectBucketCount(kContextualSearchToolsSubmissionType, |
| SubmissionType::kDeepSearch, 1); |
| } |
| |
| TEST_F(ContextualSearchMetricsRecorderTest, ToolState) { |
| // Setup user flow. |
| metrics().NotifySessionStateChanged(SessionState::kSessionStarted); |
| metrics().RecordToolState(SubmissionType::kDeepSearch, |
| AimToolState::kEnabled); |
| |
| histogram_tester().ExpectBucketCount(kContextualSearchDeepSearchToolState, |
| AimToolState::kEnabled, 1); |
| } |
| |
| TEST_F(ContextualSearchMetricsRecorderTest, TabContextAdded) { |
| metrics().NotifySessionStateChanged(SessionState::kSessionStarted); |
| metrics().RecordTabAddedMetrics(/*has_duplicate_title=*/false, std::nullopt, |
| /*is_tab_suggestion_chip=*/false); |
| metrics().RecordTabAddedMetrics(/*has_duplicate_title=*/true, std::nullopt, |
| /*is_tab_suggestion_chip=*/false); |
| DestructMetricsRecorder(); |
| |
| histogram_tester().ExpectUniqueSample(kContextualSearchTabContextAdded, 2, 1); |
| histogram_tester().ExpectUniqueSample( |
| kContextualSearchTabContextAddedFromSuggestionChip, 0, 1); |
| histogram_tester().ExpectUniqueSample( |
| kContextualSearchTabContextAddedFromPlusButton, 2, 1); |
| histogram_tester().ExpectUniqueSample( |
| kContextualSearchTabWithDuplicateTitleClicked, 1, 1); |
| |
| histogram_tester().ExpectUniqueSample( |
| kContextualSearchTabWithDuplicateTitleClicked, 1, 1); |
| |
| CreateMetricsRecorder(); |
| metrics().NotifySessionStateChanged(SessionState::kSessionStarted); |
| metrics().RecordTabAddedMetrics(/*has_duplicate_title=*/false, std::nullopt, |
| /*is_tab_suggestion_chip=*/true); |
| DestructMetricsRecorder(); |
| histogram_tester().ExpectBucketCount( |
| kContextualSearchTabContextAddedFromSuggestionChip, 1, 1); |
| } |
| |
| TEST_F(ContextualSearchMetricsRecorderTest, FileUploadSuccess) { |
| // Setup user flow. |
| metrics().NotifySessionStateChanged(SessionState::kSessionStarted); |
| task_environment().FastForwardBy(base::Seconds(30)); |
| // Simulate file upload. |
| lens::MimeType file_mime_type = lens::MimeType::kPdf; |
| FileUploadStatus upload_status = FileUploadStatus::kProcessing; |
| metrics().OnFileUploadStatusChanged(file_mime_type, upload_status, |
| std::nullopt); |
| // Finally simulate upload success. |
| upload_status = FileUploadStatus::kUploadSuccessful; |
| metrics().OnFileUploadStatusChanged(file_mime_type, upload_status, |
| std::nullopt); |
| |
| DestructMetricsRecorder(); |
| histogram_tester().ExpectTotalCount(kContextualSearchFileUploadAttemptPdf, 1); |
| histogram_tester().ExpectTotalCount(kContextualSearchFileUploadSuccessPdf, 1); |
| } |
| |
| TEST_F(ContextualSearchMetricsRecorderTest, FileUploadError) { |
| // Setup user flow. |
| metrics().NotifySessionStateChanged(SessionState::kSessionStarted); |
| task_environment().FastForwardBy(base::Seconds(30)); |
| // Simulate file upload. |
| lens::MimeType file_mime_type = lens::MimeType::kPdf; |
| FileUploadStatus upload_status = FileUploadStatus::kProcessing; |
| metrics().OnFileUploadStatusChanged(file_mime_type, upload_status, |
| std::nullopt); |
| // Next simulate file upload failure. |
| upload_status = FileUploadStatus::kUploadFailed; |
| metrics().OnFileUploadStatusChanged(file_mime_type, upload_status, |
| FileUploadErrorType::kServerError); |
| |
| DestructMetricsRecorder(); |
| histogram_tester().ExpectTotalCount(kContextualSearchFileUploadAttemptPdf, 1); |
| histogram_tester().ExpectTotalCount(kContextualSearchFileUploadServerErrorPdf, |
| 1); |
| } |
| |
| TEST_F(ContextualSearchMetricsRecorderTest, AggregatedUploadMetrics) { |
| metrics().NotifySessionStateChanged(SessionState::kSessionStarted); |
| task_environment().FastForwardBy(base::Seconds(30)); |
| |
| metrics().OnFileUploadStatusChanged( |
| lens::MimeType::kPdf, FileUploadStatus::kProcessing, std::nullopt); |
| metrics().OnFileUploadStatusChanged( |
| lens::MimeType::kPdf, FileUploadStatus::kUploadSuccessful, std::nullopt); |
| |
| metrics().OnFileUploadStatusChanged( |
| lens::MimeType::kImage, FileUploadStatus::kProcessing, std::nullopt); |
| metrics().OnFileUploadStatusChanged(lens::MimeType::kImage, |
| FileUploadStatus::kUploadFailed, |
| FileUploadErrorType::kServerError); |
| |
| DestructMetricsRecorder(); |
| |
| histogram_tester().ExpectUniqueSample(kContextualSearchFileUploadAttemptAll, |
| 2, 1); |
| |
| histogram_tester().ExpectUniqueSample(kContextualSearchFileUploadSuccessAll, |
| 1, 1); |
| |
| histogram_tester().ExpectUniqueSample(kContextualSearchFileUploadFailureAll, |
| 1, 1); |
| } |
| |
| TEST_F(ContextualSearchMetricsRecorderTest, FileValidationError) { |
| // Setup user flow. |
| FileUploadErrorType error = FileUploadErrorType::kBrowserProcessingError; |
| metrics().NotifySessionStateChanged(SessionState::kSessionStarted); |
| task_environment().FastForwardBy(base::Seconds(30)); |
| // Simulate file validation error. |
| lens::MimeType file_mime_type = lens::MimeType::kPdf; |
| uint64_t file_size = 1000000; |
| metrics().RecordFileSizeMetric(file_mime_type, file_size); |
| FileUploadStatus upload_status = FileUploadStatus::kProcessing; |
| metrics().OnFileUploadStatusChanged(file_mime_type, upload_status, |
| std::nullopt); |
| // Next simulate file validation error. |
| upload_status = FileUploadStatus::kValidationFailed; |
| metrics().OnFileUploadStatusChanged(file_mime_type, upload_status, error); |
| |
| // Simulate another file validation error. |
| upload_status = FileUploadStatus::kProcessing; |
| metrics().OnFileUploadStatusChanged(file_mime_type, upload_status, |
| std::nullopt); |
| upload_status = FileUploadStatus::kValidationFailed; |
| metrics().OnFileUploadStatusChanged(file_mime_type, upload_status, error); |
| |
| DestructMetricsRecorder(); |
| histogram_tester().ExpectBucketCount(kContextualSearchFileUploadAttemptPdf, 2, |
| 1); |
| histogram_tester().ExpectBucketCount( |
| kContextualSearchFileValidationBrowserErrorForPdf, 2, 1); |
| histogram_tester().ExpectBucketCount(kContextualSearchFileSizePdf, file_size, |
| 1); |
| } |
| |
| TEST_F(ContextualSearchMetricsRecorderTest, AggregatedFileValidationError) { |
| FileUploadErrorType error = FileUploadErrorType::kBrowserProcessingError; |
| metrics().NotifySessionStateChanged(SessionState::kSessionStarted); |
| task_environment().FastForwardBy(base::Seconds(30)); |
| |
| metrics().OnFileUploadStatusChanged( |
| lens::MimeType::kPdf, FileUploadStatus::kProcessing, std::nullopt); |
| metrics().OnFileUploadStatusChanged( |
| lens::MimeType::kPdf, FileUploadStatus::kValidationFailed, error); |
| |
| metrics().OnFileUploadStatusChanged( |
| lens::MimeType::kImage, FileUploadStatus::kProcessing, std::nullopt); |
| metrics().OnFileUploadStatusChanged( |
| lens::MimeType::kImage, FileUploadStatus::kValidationFailed, error); |
| std::string error_string = metrics().FileErrorToString(error); |
| DestructMetricsRecorder(); |
| |
| histogram_tester().ExpectUniqueSample(kContextualSearchFileUploadAttemptAll, |
| 2, 1); |
| histogram_tester().ExpectUniqueSample( |
| kContextualSearchFileValidationBrowserErrorAll, 2, 1); |
| } |
| |
| TEST_F(ContextualSearchMetricsRecorderTest, AggregatedFileSizeMetrics) { |
| metrics().NotifySessionStateChanged(SessionState::kSessionStarted); |
| metrics().RecordFileSizeMetric(lens::MimeType::kPdf, 100); |
| |
| metrics().RecordFileSizeMetric(lens::MimeType::kImage, 200); |
| DestructMetricsRecorder(); |
| |
| histogram_tester().ExpectUniqueSample(kContextualSearchFileSizePdf, 100, 1); |
| histogram_tester().ExpectUniqueSample(kContextualSearchFileSizeImage, 200, 1); |
| |
| histogram_tester().ExpectTotalCount(kContextualSearchFileSizeAll, 2); |
| histogram_tester().ExpectBucketCount(kContextualSearchFileSizeAll, 100, 1); |
| histogram_tester().ExpectBucketCount(kContextualSearchFileSizeAll, 200, 1); |
| } |
| |
| TEST_F(ContextualSearchMetricsRecorderTest, MultiFileUpload) { |
| // Setup user flow. |
| metrics().NotifySessionStateChanged(SessionState::kSessionStarted); |
| task_environment().FastForwardBy(base::Seconds(30)); |
| // Simulate unsuccessful file upload. |
| lens::MimeType file_mime_type = lens::MimeType::kPdf; |
| FileUploadStatus upload_status = FileUploadStatus::kProcessing; |
| metrics().OnFileUploadStatusChanged(file_mime_type, upload_status, |
| std::nullopt); |
| upload_status = FileUploadStatus::kUploadFailed; |
| metrics().OnFileUploadStatusChanged(file_mime_type, upload_status, |
| FileUploadErrorType::kServerError); |
| |
| // Simulate successful file upload. |
| upload_status = FileUploadStatus::kProcessing; |
| metrics().OnFileUploadStatusChanged(file_mime_type, upload_status, |
| std::nullopt); |
| upload_status = FileUploadStatus::kUploadSuccessful; |
| metrics().OnFileUploadStatusChanged(file_mime_type, upload_status, |
| std::nullopt); |
| |
| DestructMetricsRecorder(); |
| histogram_tester().ExpectBucketCount(kContextualSearchFileUploadAttemptPdf, 2, |
| 1); |
| histogram_tester().ExpectTotalCount(kContextualSearchFileUploadSuccessPdf, 1); |
| histogram_tester().ExpectTotalCount(kContextualSearchFileUploadServerErrorPdf, |
| 1); |
| } |
| |
| class MetricsRecorderFileTest |
| : public ContextualSearchMetricsRecorderTest, |
| public testing::WithParamInterface< |
| std::tuple<FileUploadStatus, lens::MimeType>> { |
| public: |
| void SetUp() override { |
| ContextualSearchMetricsRecorderTest::SetUp(); |
| metrics().NotifySessionStateChanged(SessionState::kSessionStarted); |
| metrics().OnFileUploadStatusChanged( |
| mime_type_param(), FileUploadStatus::kProcessing, std::nullopt); |
| mime_type_string_ = metrics().MimeTypeToString(mime_type_param()); |
| } |
| void TestUploadSuccessMetrics() { |
| histogram_tester().ExpectTotalCount( |
| kContextualSearchFileUploadAttempt + mime_type_string_ + |
| kContextualSearchSourceUnknownSuffix, |
| 1); |
| histogram_tester().ExpectTotalCount( |
| kContextualSearchFileUploadSuccess + mime_type_string_ + |
| kContextualSearchSourceUnknownSuffix, |
| 1); |
| } |
| void TestUploadFailureMetrics() { |
| histogram_tester().ExpectTotalCount( |
| kContextualSearchFileUploadAttempt + mime_type_string_ + |
| kContextualSearchSourceUnknownSuffix, |
| 1); |
| histogram_tester().ExpectTotalCount( |
| kContextualSearchFileUploadFailure + mime_type_string_ + |
| kContextualSearchSourceUnknownSuffix, |
| 1); |
| } |
| |
| protected: |
| FileUploadStatus status_param() const { return std::get<0>(GetParam()); } |
| lens::MimeType mime_type_param() const { return std::get<1>(GetParam()); } |
| |
| private: |
| std::string mime_type_string_; |
| }; |
| |
| TEST_P(MetricsRecorderFileTest, FileUploadStatusChanged) { |
| metrics().OnFileUploadStatusChanged(mime_type_param(), status_param(), |
| std::nullopt); |
| DestructMetricsRecorder(); |
| switch (status_param()) { |
| case FileUploadStatus::kUploadSuccessful: |
| TestUploadSuccessMetrics(); |
| break; |
| case FileUploadStatus::kUploadFailed: |
| TestUploadFailureMetrics(); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| All, |
| MetricsRecorderFileTest, |
| testing::Combine(testing::Values(FileUploadStatus::kUploadSuccessful, |
| FileUploadStatus::kUploadFailed), |
| testing::Values(lens::MimeType::kPdf, |
| lens::MimeType::kImage, |
| lens::MimeType::kAnnotatedPageContent, |
| lens::MimeType::kUnknown))); |
| |
| class MetricsRecorderFileValidationTest |
| : public ContextualSearchMetricsRecorderTest, |
| public testing::WithParamInterface< |
| std::tuple<FileUploadErrorType, lens::MimeType>> { |
| public: |
| void SetUp() override { |
| ContextualSearchMetricsRecorderTest::SetUp(); |
| metrics().NotifySessionStateChanged(SessionState::kSessionStarted); |
| metrics().OnFileUploadStatusChanged( |
| mime_type_param(), FileUploadStatus::kProcessing, std::nullopt); |
| mime_type_string_ = metrics().MimeTypeToString(mime_type_param()); |
| error_type_string_ = metrics().FileErrorToString(error_param()); |
| } |
| void TestValidationFailedMetrics() { |
| histogram_tester().ExpectTotalCount( |
| kContextualSearchFileUploadAttempt + mime_type_string_ + |
| kContextualSearchSourceUnknownSuffix, |
| 1); |
| histogram_tester().ExpectTotalCount( |
| kContextualSearchFileValidationErrorTypes + mime_type_string_ + "." + |
| error_type_string_ + kContextualSearchSourceUnknownSuffix, |
| 1); |
| } |
| |
| protected: |
| FileUploadErrorType error_param() const { return std::get<0>(GetParam()); } |
| lens::MimeType mime_type_param() const { return std::get<1>(GetParam()); } |
| |
| private: |
| std::string mime_type_string_; |
| std::string error_type_string_; |
| }; |
| |
| TEST_P(MetricsRecorderFileValidationTest, ValidationError) { |
| metrics().OnFileUploadStatusChanged( |
| mime_type_param(), FileUploadStatus::kValidationFailed, error_param()); |
| DestructMetricsRecorder(); |
| TestValidationFailedMetrics(); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| All, |
| MetricsRecorderFileValidationTest, |
| testing::Combine( |
| testing::Values(FileUploadErrorType::kUnknown, |
| FileUploadErrorType::kBrowserProcessingError, |
| FileUploadErrorType::kNetworkError, |
| FileUploadErrorType::kServerError, |
| FileUploadErrorType::kServerSizeLimitExceeded, |
| FileUploadErrorType::kAborted, |
| FileUploadErrorType::kImageProcessingError), |
| testing::Values(lens::MimeType::kPdf, |
| lens::MimeType::kImage, |
| lens::MimeType::kAnnotatedPageContent, |
| lens::MimeType::kUnknown))); |
| |
| class MetricsRecorderFileDeletionTest |
| : public ContextualSearchMetricsRecorderTest, |
| public testing::WithParamInterface< |
| std::tuple<lens::MimeType, FileUploadStatus>> { |
| public: |
| void SetUp() override { |
| ContextualSearchMetricsRecorderTest::SetUp(); |
| mime_type_string_ = metrics().MimeTypeToString(mime_type_param()); |
| status_string_ = UploadStatusToString(status_param()); |
| } |
| |
| protected: |
| lens::MimeType mime_type_param() const { return std::get<0>(GetParam()); } |
| FileUploadStatus status_param() const { return std::get<1>(GetParam()); } |
| std::string mime_type_string() const { return mime_type_string_; } |
| std::string status_string() const { return status_string_; } |
| |
| private: |
| std::string mime_type_string_; |
| std::string status_string_; |
| }; |
| |
| TEST_P(MetricsRecorderFileDeletionTest, FileDeleted) { |
| std::string file_type = "." + mime_type_string(); |
| std::string file_status = "." + status_string(); |
| // Setup user flow. |
| metrics().RecordFileDeletedMetrics(true, mime_type_param(), status_param()); |
| |
| DestructMetricsRecorder(); |
| histogram_tester().ExpectTotalCount(kContextualSearchFileDeleted + file_type + |
| file_status + |
| kContextualSearchSourceUnknownSuffix, |
| 1); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| All, |
| MetricsRecorderFileDeletionTest, |
| testing::Combine(testing::Values(lens::MimeType::kPdf, |
| lens::MimeType::kImage, |
| lens::MimeType::kAnnotatedPageContent, |
| lens::MimeType::kUnknown), |
| testing::Values(FileUploadStatus::kNotUploaded, |
| FileUploadStatus::kProcessing, |
| FileUploadStatus::kValidationFailed, |
| FileUploadStatus::kUploadStarted, |
| FileUploadStatus::kUploadSuccessful, |
| FileUploadStatus::kUploadFailed, |
| FileUploadStatus::kUploadExpired))); |
| |
| } // namespace contextual_search |