chromium/chrome/browser/android/auxiliary_search/auxiliary_search_provider_browsertest.cc

// Copyright 2023 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/android/auxiliary_search/auxiliary_search_provider.h"

#include "base/android/jni_android.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/android/persisted_tab_data/persisted_tab_data_android.h"
#include "chrome/browser/android/persisted_tab_data/sensitivity_persisted_tab_data_android.h"
#include "chrome/browser/android/tab_android.h"
#include "chrome/browser/flags/android/chrome_feature_list.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/android/tab_model/tab_model.h"
#include "chrome/browser/ui/android/tab_model/tab_model_list.h"
#include "chrome/test/base/android/android_browser_test.h"
#include "chrome/test/base/chrome_test_utils.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "url/gurl.h"
#include "url/url_constants.h"

namespace {
constexpr size_t kMaxDonatedTabs = 2;
constexpr char kMaxDonatedTabsValue[] = "2";
}  // namespace

class AuxiliarySearchProviderBrowserTest : public AndroidBrowserTest {
 public:
  AuxiliarySearchProviderBrowserTest() {
    scoped_feature_list_.InitAndEnableFeatureWithParameters(
        chrome::android::kAuxiliarySearchDonation,
        {{"auxiliary_search_max_donation_tab", kMaxDonatedTabsValue}});
  }

  void SetUpOnMainThread() override {
    host_resolver()->AddRule("*", "127.0.0.1");
    ASSERT_TRUE(embedded_test_server()->Start());
    ASSERT_TRUE(content::NavigateToURL(
        web_contents(),
        embedded_test_server()->GetURL("/android/google.html")));
    auxiliary_search_provider_ =
        std::make_unique<AuxiliarySearchProvider>(profile());
    PersistedTabDataAndroid::OnDeferredStartup();
    content::RunAllTasksUntilIdle();
  }

  content::WebContents* web_contents() {
    return chrome_test_utils::GetActiveWebContents(this);
  }

  AuxiliarySearchProvider* provider() {
    return auxiliary_search_provider_.get();
  }

  Profile* profile() {
    auto* web_contents = chrome_test_utils::GetActiveWebContents(this);
    return Profile::FromBrowserContext(web_contents->GetBrowserContext());
  }

  std::vector<raw_ptr<TabAndroid, VectorExperimental>> CreateOneTab(
      bool is_sensitive) {
    std::vector<raw_ptr<TabAndroid, VectorExperimental>> tab_vec;
    TabAndroid* tab_android = TabAndroid::FromWebContents(web_contents());
    tab_vec.push_back(tab_android);
    std::unique_ptr<SensitivityPersistedTabDataAndroid> sptda =
        std::make_unique<SensitivityPersistedTabDataAndroid>(tab_android);
    sptda->set_is_sensitive(is_sensitive);
    tab_android->SetUserData(SensitivityPersistedTabDataAndroid::UserDataKey(),
                             std::move(sptda));
    return tab_vec;
  }

 private:
  std::unique_ptr<AuxiliarySearchProvider> auxiliary_search_provider_;
  base::test::ScopedFeatureList scoped_feature_list_;
};

IN_PROC_BROWSER_TEST_F(AuxiliarySearchProviderBrowserTest, QuerySensitiveTab) {
  base::RunLoop run_loop;
  std::vector<raw_ptr<TabAndroid, VectorExperimental>> tab_vec =
      CreateOneTab(true);

  provider()->GetNonSensitiveTabsInternal(
      tab_vec, base::BindOnce(
                   [](base::OnceClosure done,
                      std::unique_ptr<std::vector<base::WeakPtr<TabAndroid>>>
                          non_Sensitive_tab) {
                     EXPECT_EQ(0u, non_Sensitive_tab->size());
                     std::move(done).Run();
                   },
                   run_loop.QuitClosure()));
  run_loop.Run();
}

IN_PROC_BROWSER_TEST_F(AuxiliarySearchProviderBrowserTest,
                       QueryNonSensitiveTab) {
  base::RunLoop run_loop;
  std::vector<raw_ptr<TabAndroid, VectorExperimental>> tab_vec =
      CreateOneTab(false);

  TabModel* tab_model = TabModelList::GetTabModelForWebContents(web_contents());
  TabAndroid* second_tab = TabAndroid::FromWebContents(web_contents());
  std::unique_ptr<content::WebContents> contents = content::WebContents::Create(
      content::WebContents::CreateParams(profile()));
  content::WebContents* second_web_contents = contents.release();
  tab_model->CreateTab(second_tab, second_web_contents, /*select=*/true);
  std::unique_ptr<SensitivityPersistedTabDataAndroid> sptda2 =
      std::make_unique<SensitivityPersistedTabDataAndroid>(second_tab);
  sptda2->set_is_sensitive(false);
  tab_vec.push_back(second_tab);

  provider()->GetNonSensitiveTabsInternal(
      tab_vec, base::BindOnce(
                   [](base::OnceClosure done,
                      std::unique_ptr<std::vector<base::WeakPtr<TabAndroid>>>
                          non_sensitive_tab) {
                     EXPECT_EQ(2u, non_sensitive_tab->size());
                     std::move(done).Run();
                   },
                   run_loop.QuitClosure()));
  run_loop.Run();
}

IN_PROC_BROWSER_TEST_F(AuxiliarySearchProviderBrowserTest,
                       QueryNonSensitiveTab_flagTest) {
  base::RunLoop run_loop;
  std::vector<raw_ptr<TabAndroid, VectorExperimental>> tab_vec =
      CreateOneTab(false);

  TabModel* tab_model = TabModelList::GetTabModelForWebContents(web_contents());
  TabAndroid* second_tab = TabAndroid::FromWebContents(web_contents());
  std::unique_ptr<content::WebContents> contents = content::WebContents::Create(
      content::WebContents::CreateParams(profile()));
  content::WebContents* second_web_contents = contents.release();
  tab_model->CreateTab(second_tab, second_web_contents, /*select=*/true);
  std::unique_ptr<SensitivityPersistedTabDataAndroid> sptda2 =
      std::make_unique<SensitivityPersistedTabDataAndroid>(second_tab);
  sptda2->set_is_sensitive(false);
  tab_vec.push_back(second_tab);

  TabAndroid* third_tab = TabAndroid::FromWebContents(web_contents());
  contents = content::WebContents::Create(
      content::WebContents::CreateParams(profile()));
  content::WebContents* third_web_contents = contents.release();
  tab_model->CreateTab(third_tab, third_web_contents, /*select=*/true);
  std::unique_ptr<SensitivityPersistedTabDataAndroid> sptda3 =
      std::make_unique<SensitivityPersistedTabDataAndroid>(third_tab);
  sptda3->set_is_sensitive(false);
  tab_vec.push_back(third_tab);

  provider()->GetNonSensitiveTabsInternal(
      tab_vec, base::BindOnce(
                   [](base::OnceClosure done,
                      std::unique_ptr<std::vector<base::WeakPtr<TabAndroid>>>
                          non_sensitive_tab) {
                     // Only 2 should be here since the flag is set to 2.
                     EXPECT_EQ(kMaxDonatedTabs, non_sensitive_tab->size());
                     std::move(done).Run();
                   },
                   run_loop.QuitClosure()));
  run_loop.Run();
}

IN_PROC_BROWSER_TEST_F(AuxiliarySearchProviderBrowserTest, QueryEmptyTabList) {
  base::RunLoop run_loop;

  provider()->GetNonSensitiveTabsInternal(
      std::vector<raw_ptr<TabAndroid, VectorExperimental>>(),
      base::BindOnce(
          [](base::OnceClosure done,
             std::unique_ptr<std::vector<base::WeakPtr<TabAndroid>>>
                 non_sensitive_tab) {
            EXPECT_EQ(0u, non_sensitive_tab->size());
            std::move(done).Run();
          },
          run_loop.QuitClosure()));
  run_loop.Run();
}

IN_PROC_BROWSER_TEST_F(AuxiliarySearchProviderBrowserTest, NativeTabTest) {
  base::RunLoop run_loop;
  ASSERT_TRUE(
      content::NavigateToURL(web_contents(), GURL(url::kAboutBlankURL)));
  std::vector<raw_ptr<TabAndroid, VectorExperimental>> tab_vec =
      CreateOneTab(false);

  provider()->GetNonSensitiveTabsInternal(
      tab_vec, base::BindOnce(
                   [](base::OnceClosure done,
                      std::unique_ptr<std::vector<base::WeakPtr<TabAndroid>>>
                          non_Sensitive_tab) {
                     EXPECT_EQ(0u, non_Sensitive_tab->size());
                     std::move(done).Run();
                   },
                   run_loop.QuitClosure()));
  run_loop.Run();
}

IN_PROC_BROWSER_TEST_F(AuxiliarySearchProviderBrowserTest, FilterTabsTest) {
  struct {
    const GURL url;
    bool should_be_filtered;
  } test_cases[]{
      {GURL(url::kAboutBlankURL), true},
      {GURL("chrome://version"), true},
      {GURL("chrome-native://newtab"), true},
      {embedded_test_server()->GetURL("/android/google.html"), false},
  };

  for (const auto& test_case : test_cases) {
    ASSERT_TRUE(content::NavigateToURL(web_contents(), test_case.url));
    std::vector<raw_ptr<TabAndroid, VectorExperimental>> tab_vec =
        CreateOneTab(false);

    std::vector<base::WeakPtr<TabAndroid>> filtered_tabs =
        AuxiliarySearchProvider::FilterTabsByScheme(tab_vec);
    EXPECT_EQ(test_case.should_be_filtered ? 0u : 1u, filtered_tabs.size());
  }
}