| // Copyright 2022 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/download/download_item_warning_data.h" |
| |
| #include <vector> |
| |
| #include "base/test/task_environment.h" |
| #include "components/download/public/common/mock_download_item.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using WarningSurface = DownloadItemWarningData::WarningSurface; |
| using WarningAction = DownloadItemWarningData::WarningAction; |
| using WarningActionEvent = DownloadItemWarningData::WarningActionEvent; |
| using DeepScanTrigger = DownloadItemWarningData::DeepScanTrigger; |
| using ::testing::Return; |
| |
| class DownloadItemWarningDataTest : public testing::Test { |
| public: |
| DownloadItemWarningDataTest() { |
| ON_CALL(download_, IsDangerous()).WillByDefault(Return(true)); |
| } |
| |
| protected: |
| void FastForwardAndAddEvent(base::TimeDelta time_delta, |
| WarningSurface surface, |
| WarningAction action) { |
| task_environment_.FastForwardBy(time_delta); |
| DownloadItemWarningData::AddWarningActionEvent(&download_, surface, action); |
| } |
| |
| std::vector<WarningActionEvent> GetEvents() { |
| return DownloadItemWarningData::GetWarningActionEvents(&download_); |
| } |
| |
| bool VerifyEventValue(const WarningActionEvent& actual_event, |
| WarningSurface expected_surface, |
| WarningAction expected_action, |
| int64_t expected_latency, |
| bool expected_is_terminal_action) { |
| bool success = true; |
| if (actual_event.surface != expected_surface) { |
| success = false; |
| ADD_FAILURE() << "Warning action event should have surface " |
| << static_cast<int>(expected_surface) << ", but found " |
| << static_cast<int>(actual_event.surface); |
| } |
| if (actual_event.action != expected_action) { |
| success = false; |
| ADD_FAILURE() << "Warning action event should have action " |
| << static_cast<int>(expected_action) << ", but found " |
| << static_cast<int>(actual_event.action); |
| } |
| if (actual_event.action_latency_msec != expected_latency) { |
| success = false; |
| ADD_FAILURE() << "Warning action event should have latency " |
| << expected_latency << ", but found " |
| << actual_event.action_latency_msec; |
| } |
| if (actual_event.is_terminal_action != expected_is_terminal_action) { |
| success = false; |
| ADD_FAILURE() << "Warning action event should have is_terminal_action " |
| << expected_is_terminal_action << ", but found " |
| << actual_event.is_terminal_action; |
| } |
| return success; |
| } |
| |
| base::test::TaskEnvironment task_environment_{ |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME}; |
| download::MockDownloadItem download_; |
| }; |
| |
| TEST_F(DownloadItemWarningDataTest, GetEvents) { |
| FastForwardAndAddEvent(base::Seconds(0), WarningSurface::BUBBLE_MAINPAGE, |
| WarningAction::SHOWN); |
| FastForwardAndAddEvent(base::Seconds(5), WarningSurface::BUBBLE_SUBPAGE, |
| WarningAction::CLOSE); |
| FastForwardAndAddEvent(base::Seconds(10), WarningSurface::DOWNLOAD_PROMPT, |
| WarningAction::CANCEL); |
| FastForwardAndAddEvent(base::Seconds(15), WarningSurface::DOWNLOADS_PAGE, |
| WarningAction::DISCARD); |
| |
| std::vector<WarningActionEvent> events = GetEvents(); |
| |
| ASSERT_EQ(3u, events.size()); |
| EXPECT_TRUE(VerifyEventValue(events[0], WarningSurface::BUBBLE_SUBPAGE, |
| WarningAction::CLOSE, /*expected_latency=*/5000, |
| /*expected_is_terminal_action=*/false)); |
| EXPECT_TRUE(VerifyEventValue( |
| events[1], WarningSurface::DOWNLOAD_PROMPT, WarningAction::CANCEL, |
| /*expected_latency=*/15000, /*expected_is_terminal_action=*/false)); |
| EXPECT_TRUE(VerifyEventValue( |
| events[2], WarningSurface::DOWNLOADS_PAGE, WarningAction::DISCARD, |
| /*expected_latency=*/30000, /*expected_is_terminal_action=*/true)); |
| } |
| |
| TEST_F(DownloadItemWarningDataTest, GetEvents_Notification) { |
| FastForwardAndAddEvent(base::Seconds(0), |
| WarningSurface::DOWNLOAD_NOTIFICATION, |
| WarningAction::SHOWN); |
| FastForwardAndAddEvent(base::Seconds(5), |
| WarningSurface::DOWNLOAD_NOTIFICATION, |
| WarningAction::OPEN_SUBPAGE); |
| |
| std::vector<WarningActionEvent> events = GetEvents(); |
| |
| ASSERT_EQ(1u, events.size()); |
| EXPECT_TRUE(VerifyEventValue(events[0], WarningSurface::DOWNLOAD_NOTIFICATION, |
| WarningAction::OPEN_SUBPAGE, |
| /*expected_latency=*/5000, |
| /*expected_is_terminal_action=*/false)); |
| } |
| |
| TEST_F(DownloadItemWarningDataTest, GetEvents_WarningShownNotLogged) { |
| FastForwardAndAddEvent(base::Seconds(5), WarningSurface::BUBBLE_SUBPAGE, |
| WarningAction::PROCEED); |
| |
| std::vector<WarningActionEvent> events = GetEvents(); |
| |
| // The events are not logged because the SHOWN event is not logged, so there |
| // is no anchor event to calculate the latency. |
| EXPECT_EQ(0u, events.size()); |
| } |
| |
| TEST_F(DownloadItemWarningDataTest, GetEvents_NotDangerous) { |
| ON_CALL(download_, IsDangerous()).WillByDefault(Return(false)); |
| FastForwardAndAddEvent(base::Seconds(0), WarningSurface::BUBBLE_MAINPAGE, |
| WarningAction::SHOWN); |
| FastForwardAndAddEvent(base::Seconds(5), WarningSurface::BUBBLE_SUBPAGE, |
| WarningAction::PROCEED); |
| |
| std::vector<WarningActionEvent> events = GetEvents(); |
| |
| // The events are not logged because download is not dangerous. |
| EXPECT_EQ(0u, events.size()); |
| } |
| |
| TEST_F(DownloadItemWarningDataTest, GetEvents_MultipleWarningShownLogged) { |
| FastForwardAndAddEvent(base::Seconds(0), WarningSurface::BUBBLE_MAINPAGE, |
| WarningAction::SHOWN); |
| FastForwardAndAddEvent(base::Seconds(5), WarningSurface::BUBBLE_MAINPAGE, |
| WarningAction::SHOWN); |
| FastForwardAndAddEvent(base::Seconds(5), |
| WarningSurface::DOWNLOAD_NOTIFICATION, |
| WarningAction::SHOWN); |
| FastForwardAndAddEvent(base::Seconds(5), WarningSurface::BUBBLE_SUBPAGE, |
| WarningAction::DISCARD); |
| |
| std::vector<WarningActionEvent> events = GetEvents(); |
| |
| ASSERT_EQ(1u, events.size()); |
| // The expected latency should be 15000 instead of 5000 because the latency |
| // should be anchored to the first shown event. |
| EXPECT_TRUE(VerifyEventValue(events[0], WarningSurface::BUBBLE_SUBPAGE, |
| WarningAction::DISCARD, |
| /*expected_latency=*/15000, |
| /*expected_is_terminal_action=*/true)); |
| } |
| |
| TEST_F(DownloadItemWarningDataTest, GetEvents_ExceedEventMaxLength) { |
| FastForwardAndAddEvent(base::Seconds(0), WarningSurface::BUBBLE_MAINPAGE, |
| WarningAction::SHOWN); |
| for (int i = 0; i <= 30; i++) { |
| FastForwardAndAddEvent(base::Seconds(5), WarningSurface::BUBBLE_SUBPAGE, |
| WarningAction::CLOSE); |
| } |
| |
| std::vector<WarningActionEvent> events = GetEvents(); |
| |
| ASSERT_EQ(20u, events.size()); |
| // The newer events should be ignored, so the expected latency of the last |
| // event should be the 20th event. |
| EXPECT_TRUE(VerifyEventValue(events[19], WarningSurface::BUBBLE_SUBPAGE, |
| WarningAction::CLOSE, |
| /*expected_latency=*/20 * 5000, |
| /*expected_is_terminal_action=*/false)); |
| } |
| |
| TEST_F(DownloadItemWarningDataTest, IsEncryptedArchive) { |
| EXPECT_FALSE(DownloadItemWarningData::IsTopLevelEncryptedArchive(&download_)); |
| DownloadItemWarningData::SetIsTopLevelEncryptedArchive(&download_, true); |
| EXPECT_TRUE(DownloadItemWarningData::IsTopLevelEncryptedArchive(&download_)); |
| } |
| |
| TEST_F(DownloadItemWarningDataTest, HasIncorrectPassword) { |
| EXPECT_FALSE(DownloadItemWarningData::HasIncorrectPassword(&download_)); |
| DownloadItemWarningData::SetHasIncorrectPassword(&download_, true); |
| EXPECT_TRUE(DownloadItemWarningData::HasIncorrectPassword(&download_)); |
| } |
| |
| TEST_F(DownloadItemWarningDataTest, HasShownLocalDecryptionPrompt) { |
| EXPECT_FALSE( |
| DownloadItemWarningData::HasShownLocalDecryptionPrompt(&download_)); |
| DownloadItemWarningData::SetHasShownLocalDecryptionPrompt(&download_, true); |
| EXPECT_TRUE( |
| DownloadItemWarningData::HasShownLocalDecryptionPrompt(&download_)); |
| } |
| |
| TEST_F(DownloadItemWarningDataTest, DeepScanTrigger) { |
| EXPECT_EQ(DownloadItemWarningData::DownloadDeepScanTrigger(&download_), |
| DeepScanTrigger::TRIGGER_UNKNOWN); |
| DownloadItemWarningData::SetDeepScanTrigger( |
| &download_, DeepScanTrigger::TRIGGER_CONSUMER_PROMPT); |
| EXPECT_EQ(DownloadItemWarningData::DownloadDeepScanTrigger(&download_), |
| DeepScanTrigger::TRIGGER_CONSUMER_PROMPT); |
| } |
| |
| TEST_F(DownloadItemWarningDataTest, FirstShownTimeAndSurface) { |
| EXPECT_EQ(DownloadItemWarningData::WarningFirstShownSurface(&download_), |
| std::nullopt); |
| EXPECT_TRUE( |
| DownloadItemWarningData::WarningFirstShownTime(&download_).is_null()); |
| base::Time now = base::Time::Now(); |
| FastForwardAndAddEvent(base::Seconds(0), |
| WarningSurface::DOWNLOAD_NOTIFICATION, |
| WarningAction::SHOWN); |
| FastForwardAndAddEvent(base::Seconds(5), WarningSurface::BUBBLE_MAINPAGE, |
| WarningAction::SHOWN); |
| |
| EXPECT_EQ(*DownloadItemWarningData::WarningFirstShownSurface(&download_), |
| WarningSurface::DOWNLOAD_NOTIFICATION); |
| EXPECT_EQ(DownloadItemWarningData::WarningFirstShownTime(&download_), now); |
| } |
| |
| TEST_F(DownloadItemWarningDataTest, EventToString) { |
| FastForwardAndAddEvent(base::Seconds(0), WarningSurface::BUBBLE_MAINPAGE, |
| WarningAction::SHOWN); |
| FastForwardAndAddEvent(base::Seconds(5), WarningSurface::BUBBLE_SUBPAGE, |
| WarningAction::CLOSE); |
| FastForwardAndAddEvent(base::Seconds(10), WarningSurface::DOWNLOAD_PROMPT, |
| WarningAction::CANCEL); |
| FastForwardAndAddEvent(base::Seconds(15), WarningSurface::DOWNLOADS_PAGE, |
| WarningAction::DISCARD); |
| |
| std::vector<WarningActionEvent> events = GetEvents(); |
| |
| // The initial SHOWN event is not included. |
| EXPECT_EQ(events[0].ToString(), "BUBBLE_SUBPAGE:CLOSE:5000"); |
| EXPECT_EQ(events[1].ToString(), "DOWNLOAD_PROMPT:CANCEL:15000"); |
| EXPECT_EQ(events[2].ToString(), "DOWNLOADS_PAGE:DISCARD:30000"); |
| } |