text: // Copyright 2020 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/safe_browsing/chrome_enterprise_url_lookup_service.h"
  
  #include "base/test/metrics/histogram_tester.h"
  #include "base/test/mock_callback.h"
  #include "chrome/browser/safe_browsing/dm_token_utils.h"
  #include "chrome/test/base/testing_profile.h"
  #include "components/content_settings/core/browser/host_content_settings_map.h"
  #include "components/policy/core/common/cloud/dm_token.h"
  #include "components/safe_browsing/core/proto/csd.pb.h"
  #include "components/safe_browsing/core/verdict_cache_manager.h"
  #include "components/sync/driver/test_sync_service.h"
  #include "components/sync_preferences/testing_pref_service_syncable.h"
  #include "content/public/test/browser_task_environment.h"
  #include "services/network/public/cpp/shared_url_loader_factory.h"
  #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
  #include "services/network/test/test_url_loader_factory.h"
  #include "testing/platform_test.h"
  
  using ::testing::_;
  
  namespace safe_browsing {
  
  namespace {
  constexpr char kRealTimeLookupUrl[] =
      "https://safebrowsing.google.com/safebrowsing/clientreport/realtime";
  }  // namespace
  
  class ChromeEnterpriseRealTimeUrlLookupServiceTest : public PlatformTest {
   public:
    void SetUp() override {
      HostContentSettingsMap::RegisterProfilePrefs(test_pref_service_.registry());
      safe_browsing::RegisterProfilePrefs(test_pref_service_.registry());
      PlatformTest::SetUp();
  
      test_shared_loader_factory_ =
          base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
              &test_url_loader_factory_);
  
      content_setting_map_ = new HostContentSettingsMap(
          &test_pref_service_, false /* is_off_the_record */,
          false /* store_last_modified */,
          false /* migrate_requesting_and_top_level_origin_settings */,
          false /* restore_session */);
      cache_manager_ = std::make_unique<VerdictCacheManager>(
          nullptr, content_setting_map_.get());
  
      TestingProfile::Builder builder;
      test_profile_ = builder.Build();
  
      enterprise_rt_service_ =
          std::make_unique<ChromeEnterpriseRealTimeUrlLookupService>(
              test_shared_loader_factory_, cache_manager_.get(),
              test_profile_.get(), &test_sync_service_, &test_pref_service_,
              ChromeUserPopulation::NOT_MANAGED,
              /*is_under_advanced_protection=*/true,
              /*is_off_the_record=*/false);
    }
  
    void TearDown() override {
      cache_manager_.reset();
      content_setting_map_->ShutdownOnUIThread();
    }
  
    std::unique_ptr<RTLookupResponse> GetCachedRealTimeUrlVerdict(
        const GURL& url) {
      return enterprise_rt_service_->GetCachedRealTimeUrlVerdict(url);
    }
  
    void MayBeCacheRealTimeUrlVerdict(
        GURL url,
        RTLookupResponse::ThreatInfo::VerdictType verdict_type,
        RTLookupResponse::ThreatInfo::ThreatType threat_type,
        int cache_duration_sec,
        const std::string& cache_expression,
        RTLookupResponse::ThreatInfo::CacheExpressionMatchType
            cache_expression_match_type) {
      RTLookupResponse response;
      RTLookupResponse::ThreatInfo* new_threat_info = response.add_threat_info();
      new_threat_info->set_verdict_type(verdict_type);
      new_threat_info->set_threat_type(threat_type);
      new_threat_info->set_cache_duration_sec(cache_duration_sec);
      new_threat_info->set_cache_expression_using_match_type(cache_expression);
      new_threat_info->set_cache_expression_match_type(
          cache_expression_match_type);
      enterprise_rt_service_->MayBeCacheRealTimeUrlVerdict(url, response);
    }
  
    void SetUpRTLookupResponse(
        RTLookupResponse::ThreatInfo::VerdictType verdict_type,
        RTLookupResponse::ThreatInfo::ThreatType threat_type,
        int cache_duration_sec,
        const std::string& cache_expression,
        RTLookupResponse::ThreatInfo::CacheExpressionMatchType
            cache_expression_match_type) {
      RTLookupResponse response;
      RTLookupResponse::ThreatInfo* new_threat_info = response.add_threat_info();
      RTLookupResponse::ThreatInfo threat_info;
      threat_info.set_verdict_type(verdict_type);
      threat_info.set_threat_type(threat_type);
      threat_info.set_cache_duration_sec(cache_duration_sec);
      threat_info.set_cache_expression_using_match_type(cache_expression);
      threat_info.set_cache_expression_match_type(cache_expression_match_type);
      *new_threat_info = threat_info;
      std::string expected_response_str;
      response.SerializeToString(&expected_response_str);
      test_url_loader_factory_.AddResponse(kRealTimeLookupUrl,
                                           expected_response_str);
    }
  
    ChromeEnterpriseRealTimeUrlLookupService* enterprise_rt_service() {
      return enterprise_rt_service_.get();
    }
  
    network::TestURLLoaderFactory test_url_loader_factory_;
    scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
    std::unique_ptr<ChromeEnterpriseRealTimeUrlLookupService>
        enterprise_rt_service_;
    std::unique_ptr<VerdictCacheManager> cache_manager_;
    scoped_refptr<HostContentSettingsMap> content_setting_map_;
    content::BrowserTaskEnvironment task_environment_;
    sync_preferences::TestingPrefServiceSyncable test_pref_service_;
    std::unique_ptr<TestingProfile> test_profile_;
    syncer::TestSyncService test_sync_service_;
  };
  
  TEST_F(ChromeEnterpriseRealTimeUrlLookupServiceTest,
         TestStartLookup_ResponseIsAlreadyCached) {
    GURL url("http://example.test/");
    MayBeCacheRealTimeUrlVerdict(url, RTLookupResponse::ThreatInfo::DANGEROUS,
                                 RTLookupResponse::ThreatInfo::SOCIAL_ENGINEERING,
                                 60, "example.test/",
                                 RTLookupResponse::ThreatInfo::COVERING_MATCH);
    task_environment_.RunUntilIdle();
  
    base::MockCallback<RTLookupRequestCallback> request_callback;
    base::MockCallback<RTLookupResponseCallback> response_callback;
    enterprise_rt_service()->StartLookup(url, request_callback.Get(),
                                         response_callback.Get());
  
    // |request_callback| should not be called if the verdict is already cached.
    EXPECT_CALL(request_callback, Run(_, _)).Times(0);
    EXPECT_CALL(response_callback, Run(/* is_rt_lookup_successful */ true, _));
  
    task_environment_.RunUntilIdle();
  }
  
  TEST_F(ChromeEnterpriseRealTimeUrlLookupServiceTest,
         TestStartLookup_RequestWithDmToken) {
    GURL url("http://example.test/");
    SetUpRTLookupResponse(RTLookupResponse::ThreatInfo::DANGEROUS,
                          RTLookupResponse::ThreatInfo::SOCIAL_ENGINEERING, 60,
                          "example.test/",
                          RTLookupResponse::ThreatInfo::COVERING_MATCH);
    SetDMTokenForTesting(policy::DMToken::CreateValidTokenForTesting("dm_token"));
  
    base::MockCallback<RTLookupResponseCallback> response_callback;
    enterprise_rt_service()->StartLookup(
        url,
        base::BindOnce(
            [](std::unique_ptr<RTLookupRequest> request, std::string token) {
              EXPECT_EQ("http://example.test/", request->url());
              EXPECT_EQ("dm_token", request->dm_token());
              EXPECT_EQ(ChromeUserPopulation::SAFE_BROWSING,
                        request->population().user_population());
              EXPECT_TRUE(request->population().is_history_sync_enabled());
              EXPECT_EQ(ChromeUserPopulation::NOT_MANAGED,
                        request->population().profile_management_status());
              EXPECT_TRUE(request->population().is_under_advanced_protection());
              EXPECT_EQ("", token);
            }),
        response_callback.Get());
  
    EXPECT_CALL(response_callback, Run(/* is_rt_lookup_successful */ true, _));
  
    task_environment_.RunUntilIdle();
  
    // Check the response is cached.
    EXPECT_NE(nullptr, GetCachedRealTimeUrlVerdict(url));
  }
  
  }  // namespace safe_browsing
  