web_bluetooth_browsertest.cc 7.44 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
// Copyright 2016 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.

// This file contains browsertests for Web Bluetooth that depend on behavior
// defined in chrome/, not just in content/.

#include "base/command_line.h"
#include "base/metrics/field_trial.h"
#include "chrome/browser/permissions/permission_context_base.h"
#include "chrome/browser/ui/browser.h"
12
#include "chrome/browser/ui/browser_commands.h"
13 14 15 16 17
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/variations/variations_associated_data.h"
#include "content/public/browser/render_frame_host.h"
18
#include "content/public/browser/render_process_host.h"
19 20 21 22 23
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test_utils.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"

24 25 26 27 28
using device::MockBluetoothAdapter;
using testing::Return;

typedef testing::NiceMock<MockBluetoothAdapter> NiceMockBluetoothAdapter;

29 30 31 32 33
namespace {

class WebBluetoothTest : public InProcessBrowserTest {
 protected:
  void SetUpCommandLine(base::CommandLine* command_line) override {
34 35 36 37 38 39
    // TODO(juncai): Remove this switch once Web Bluetooth is supported on Linux
    // and Windows.
    // https://crbug.com/570344
    // https://crbug.com/507419
    command_line->AppendSwitch(
        switches::kEnableExperimentalWebPlatformFeatures);
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
  }

  void SetUpOnMainThread() override {
    // Navigate to a secure context.
    embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data");
    ASSERT_TRUE(embedded_test_server()->Start());
    ui_test_utils::NavigateToURL(
        browser(),
        embedded_test_server()->GetURL("localhost", "/simple_page.html"));
    web_contents_ = browser()->tab_strip_model()->GetActiveWebContents();
    EXPECT_THAT(
        web_contents_->GetMainFrame()->GetLastCommittedOrigin().Serialize(),
        testing::StartsWith("http://localhost:"));
  }

  content::WebContents* web_contents_ = nullptr;
};

58 59 60 61 62 63 64
IN_PROC_BROWSER_TEST_F(WebBluetoothTest, WebBluetoothAfterCrash) {
  // Make sure we can use Web Bluetooth after the tab crashes.
  // Set up adapter with one device.
  scoped_refptr<NiceMockBluetoothAdapter> adapter(
      new NiceMockBluetoothAdapter());
  ON_CALL(*adapter, IsPresent()).WillByDefault(Return(false));

65 66 67
  auto bt_global_values =
      device::BluetoothAdapterFactory::Get().InitGlobalValuesForTesting();
  bt_global_values->SetLESupported(true);
68 69 70 71 72 73 74 75 76 77 78
  device::BluetoothAdapterFactory::SetAdapterForTesting(adapter);

  std::string result;
  EXPECT_TRUE(content::ExecuteScriptAndExtractString(
      web_contents_,
      "navigator.bluetooth.requestDevice({filters: [{services: [0x180d]}]})"
      "  .catch(e => domAutomationController.send(e.toString()));",
      &result));
  EXPECT_EQ("NotFoundError: Bluetooth adapter not available.", result);

  // Crash the renderer process.
79 80
  content::RenderProcessHost* process =
      web_contents_->GetMainFrame()->GetProcess();
81 82 83 84 85 86
  content::RenderProcessHostWatcher crash_observer(
      process, content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
  process->Shutdown(0, false);
  crash_observer.Wait();

  // Reload tab.
87
  chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
88 89 90 91 92 93 94 95 96 97 98 99 100 101
  content::WaitForLoadStop(
      browser()->tab_strip_model()->GetActiveWebContents());

  // Use Web Bluetooth again.
  std::string result_after_crash;
  EXPECT_TRUE(content::ExecuteScriptAndExtractString(
      web_contents_,
      "navigator.bluetooth.requestDevice({filters: [{services: [0x180d]}]})"
      "  .catch(e => domAutomationController.send(e.toString()));",
      &result_after_crash));
  EXPECT_EQ("NotFoundError: Bluetooth adapter not available.",
            result_after_crash);
}

102 103 104 105
IN_PROC_BROWSER_TEST_F(WebBluetoothTest, KillSwitchShouldBlock) {
  // Fake the BluetoothAdapter to say it's present.
  scoped_refptr<device::MockBluetoothAdapter> adapter =
      new testing::NiceMock<device::MockBluetoothAdapter>;
106
  EXPECT_CALL(*adapter, IsPresent()).WillRepeatedly(Return(true));
107 108 109
  auto bt_global_values =
      device::BluetoothAdapterFactory::Get().InitGlobalValuesForTesting();
  bt_global_values->SetLESupported(true);
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
  device::BluetoothAdapterFactory::SetAdapterForTesting(adapter);

  // Turn on the global kill switch.
  std::map<std::string, std::string> params;
  params["Bluetooth"] =
      PermissionContextBase::kPermissionsKillSwitchBlockedValue;
  variations::AssociateVariationParams(
      PermissionContextBase::kPermissionsKillSwitchFieldStudy, "TestGroup",
      params);
  base::FieldTrialList::CreateFieldTrial(
      PermissionContextBase::kPermissionsKillSwitchFieldStudy, "TestGroup");

  std::string rejection;
  EXPECT_TRUE(content::ExecuteScriptAndExtractString(
      web_contents_,
      "navigator.bluetooth.requestDevice({filters: [{name: 'Hello'}]})"
      "  .then(() => { domAutomationController.send('Success'); },"
      "        reason => {"
      "      domAutomationController.send(reason.name + ': ' + reason.message);"
      "  });",
      &rejection));
  EXPECT_THAT(rejection,
              testing::MatchesRegex("NotFoundError: .*globally disabled.*"));
}

135
// Tests that using Finch field trial parameters for blocklist additions has
136
// the effect of rejecting requestDevice calls.
137
IN_PROC_BROWSER_TEST_F(WebBluetoothTest, BlocklistShouldBlock) {
138 139 140
  // Fake the BluetoothAdapter to say it's present.
  scoped_refptr<device::MockBluetoothAdapter> adapter =
      new testing::NiceMock<device::MockBluetoothAdapter>;
141
  EXPECT_CALL(*adapter, IsPresent()).WillRepeatedly(Return(true));
142 143 144
  auto bt_global_values =
      device::BluetoothAdapterFactory::Get().InitGlobalValuesForTesting();
  bt_global_values->SetLESupported(true);
145 146
  device::BluetoothAdapterFactory::SetAdapterForTesting(adapter);

147 148 149 150
  if (base::FieldTrialList::TrialExists("WebBluetoothBlocklist")) {
    LOG(INFO) << "WebBluetoothBlocklist field trial already configured.";
    ASSERT_NE(variations::GetVariationParamValue("WebBluetoothBlocklist",
                                                 "blocklist_additions")
151 152
                  .find("ed5f25a4"),
              std::string::npos)
153
        << "ERROR: WebBluetoothBlocklist field trial being tested in\n"
154 155
           "testing/variations/fieldtrial_testing_config_*.json must\n"
           "include this test's random UUID 'ed5f25a4' in\n"
156
           "blocklist_additions.\n";
157
  } else {
158
    LOG(INFO) << "Creating WebBluetoothBlocklist field trial for test.";
159 160
    // Create a field trial with test parameter.
    std::map<std::string, std::string> params;
161 162
    params["blocklist_additions"] = "ed5f25a4:e";
    variations::AssociateVariationParams("WebBluetoothBlocklist", "TestGroup",
163
                                         params);
164
    base::FieldTrialList::CreateFieldTrial("WebBluetoothBlocklist",
165 166
                                           "TestGroup");
  }
167 168 169 170

  std::string rejection;
  EXPECT_TRUE(content::ExecuteScriptAndExtractString(
      web_contents_,
171
      "navigator.bluetooth.requestDevice({filters: [{services: [0xed5f25a4]}]})"
172 173 174 175 176 177
      "  .then(() => { domAutomationController.send('Success'); },"
      "        reason => {"
      "      domAutomationController.send(reason.name + ': ' + reason.message);"
      "  });",
      &rejection));
  EXPECT_THAT(rejection,
178
              testing::MatchesRegex("SecurityError: .*blocklisted UUID.*"));
179 180
}

181
}  // namespace