Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(913)

Unified Diff: chrome/browser/devtools/device/usb/android_usb_browsertest.cc

Issue 315923003: DevTools: Tests for DevToolsAndroidBridge device polling (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Added test for non-Android devices Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | chrome/browser/devtools/device/usb/devtools_android_bridge_browsertest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/devtools/device/usb/android_usb_browsertest.cc
diff --git a/chrome/browser/devtools/device/usb/android_usb_browsertest.cc b/chrome/browser/devtools/device/usb/android_usb_browsertest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..172632405d43329f5420592912f707949f57b6d1
--- /dev/null
+++ b/chrome/browser/devtools/device/usb/android_usb_browsertest.cc
@@ -0,0 +1,855 @@
+// Copyright 2014 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 <algorithm>
+
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/devtools/device/devtools_android_bridge.h"
+#include "chrome/browser/devtools/device/usb/android_usb_device.h"
+#include "chrome/browser/devtools/device/usb/usb_device_provider.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "components/usb_service/usb_device.h"
+#include "components/usb_service/usb_device_handle.h"
+#include "components/usb_service/usb_interface.h"
+#include "components/usb_service/usb_service.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using content::BrowserThread;
+using namespace usb_service;
+
+namespace {
+
+struct AndroidTraits {
+ static const int kClass = 0xff;
+ static const int kSubclass = 0x42;
+ static const int kProtocol = 0x1;
+};
+
+struct NonAndroidTraits {
+ static const int kClass = 0xf0;
+ static const int kSubclass = 0x42;
+ static const int kProtocol = 0x2;
+};
+
+const uint32 kMaxPayload = 4096;
+const uint32 kVersion = 0x01000000;
+
+const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix";
+const char kDeviceModelCommand[] = "shell:getprop ro.product.model";
+const char kDumpsysCommand[] = "shell:dumpsys window policy";
+const char kListProcessesCommand[] = "shell:ps";
+const char kInstalledChromePackagesCommand[] = "shell:pm list packages";
+const char kDeviceModel[] = "Nexus 5";
+const char kDeviceSerial[] = "Sample serial";
+
+const char kSampleOpenedUnixSockets[] =
+ "Num RefCount Protocol Flags Type St Inode Path\n"
+ "00000000: 00000004 00000000"
+ " 00000000 0002 01 3328 /dev/socket/wpa_wlan0\n"
+ "00000000: 00000002 00000000"
+ " 00010000 0001 01 5394 /dev/socket/vold\n";
+
+const char kSampleListProcesses[] =
+ "USER PID PPID VSIZE RSS WCHAN PC NAME\n"
+ "root 1 0 688 508 ffffffff 00000000 S /init\r\n"
+ "u0_a75 2425 123 933736 193024 ffffffff 00000000 S com.sample.feed\r\n"
+ "nfc 741 123 706448 26316 ffffffff 00000000 S com.android.nfc\r\n"
+ "u0_a76 1001 124 111111 222222 ffffffff 00000000 S com.android.chrome\r\n"
+ "u0_a78 1003 126 111111 222222 ffffffff 00000000 S com.noprocess.app\r\n";
+
+const char kSampleListPackages[] =
+ "package:com.sample.feed\r\n"
+ "package:com.android.nfc\r\n"
+ "package:com.android.chrome\r\n"
+ "package:com.chrome.beta\r\n"
+ "package:com.google.android.apps.chrome\r\n";
+
+const char kSampleDumpsys[] =
+ "WINDOW MANAGER POLICY STATE (dumpsys window policy)\r\n"
+ " mSafeMode=false mSystemReady=true mSystemBooted=true\r\n"
+ " mStable=(0,50)-(720,1184)\r\n" // Only mStable parameter is parsed
+ " mForceStatusBar=false mForceStatusBarFromKeyguard=false\r\n";
+
+const char* GetMockShellResponse(std::string command) {
+ if (command == kDeviceModelCommand) {
+ return kDeviceModel;
+ } else if (command == kOpenedUnixSocketsCommand) {
+ return kSampleOpenedUnixSockets;
+ } else if (command == kDumpsysCommand) {
+ return kSampleDumpsys;
+ } else if (command == kListProcessesCommand) {
+ return kSampleListProcesses;
+ } else if (command == kInstalledChromePackagesCommand) {
+ return kSampleListPackages;
+ }
+
+ DCHECK(false) << "Should not be reached";
+
+ return "";
+}
+
+class MockUsbEndpointDescriptor : public UsbEndpointDescriptor {
+ public:
+ virtual int GetAddress() const OVERRIDE { return address_; }
+
+ virtual UsbEndpointDirection GetDirection() const OVERRIDE {
+ return direction_;
+ }
+
+ virtual int GetMaximumPacketSize() const OVERRIDE {
+ return maximum_packet_size_;
+ }
+
+ virtual UsbSynchronizationType GetSynchronizationType() const OVERRIDE {
+ return usb_synchronization_type_;
+ }
+
+ virtual UsbTransferType GetTransferType() const OVERRIDE {
+ return usb_transfer_type_;
+ }
+ virtual UsbUsageType GetUsageType() const OVERRIDE { return usb_usage_type_; }
+
+ virtual int GetPollingInterval() const OVERRIDE { return polling_interval_; }
+
+ int address_;
+ UsbEndpointDirection direction_;
+ int maximum_packet_size_;
+ UsbSynchronizationType usb_synchronization_type_;
+ UsbTransferType usb_transfer_type_;
+ UsbUsageType usb_usage_type_;
+ int polling_interval_;
+
+ private:
+ virtual ~MockUsbEndpointDescriptor() {}
+};
+
+template <class T>
+class MockUsbInterfaceAltSettingDescriptor
+ : public UsbInterfaceAltSettingDescriptor {
+ public:
+ MockUsbInterfaceAltSettingDescriptor(int interface_number,
+ int alternate_setting)
+ : interface_number_(interface_number),
+ alternate_setting_(alternate_setting) {}
+
+ virtual size_t GetNumEndpoints() const OVERRIDE {
+ // See IsAndroidInterface function in android_usb_device.cc
+ return 2;
+ }
+
+ virtual scoped_refptr<const UsbEndpointDescriptor> GetEndpoint(
+ size_t index) const OVERRIDE {
+ EXPECT_GT(static_cast<size_t>(2), index);
+ MockUsbEndpointDescriptor* result = new MockUsbEndpointDescriptor();
+ result->address_ = index + 1;
+ result->usb_transfer_type_ = USB_TRANSFER_BULK;
+ result->direction_ =
+ ((index == 0) ? USB_DIRECTION_INBOUND : USB_DIRECTION_OUTBOUND);
+ result->maximum_packet_size_ = 1 << 20; // 1Mb maximum packet size
+ return result;
+ }
+
+ virtual int GetInterfaceNumber() const OVERRIDE { return interface_number_; }
+
+ virtual int GetAlternateSetting() const OVERRIDE {
+ return alternate_setting_;
+ }
+
+ virtual int GetInterfaceClass() const OVERRIDE { return T::kClass; }
+
+ virtual int GetInterfaceSubclass() const OVERRIDE { return T::kSubclass; }
+
+ virtual int GetInterfaceProtocol() const OVERRIDE { return T::kProtocol; }
+
+ protected:
+ virtual ~MockUsbInterfaceAltSettingDescriptor() {};
+
+ private:
+ const int interface_number_;
+ const int alternate_setting_;
+};
+
+template <class T>
+class MockUsbInterfaceDescriptor : public UsbInterfaceDescriptor {
+ public:
+ explicit MockUsbInterfaceDescriptor(int interface_number)
+ : interface_number_(interface_number) {}
+
+ virtual size_t GetNumAltSettings() const OVERRIDE {
+ // See IsAndroidInterface function in android_usb_device.cc
+ return 1;
+ }
+ virtual scoped_refptr<const UsbInterfaceAltSettingDescriptor> GetAltSetting(
+ size_t index) const OVERRIDE {
+ EXPECT_EQ(static_cast<size_t>(0), index);
+ return new MockUsbInterfaceAltSettingDescriptor<T>(interface_number_, 0);
+ }
+
+ protected:
+ const int interface_number_;
+ virtual ~MockUsbInterfaceDescriptor() {}
+};
+
+template <class T>
+class MockUsbConfigDescriptor : public UsbConfigDescriptor {
+ public:
+ MockUsbConfigDescriptor() {}
+
+ virtual size_t GetNumInterfaces() const OVERRIDE { return 1; }
+
+ virtual scoped_refptr<const UsbInterfaceDescriptor> GetInterface(
+ size_t index) const OVERRIDE {
+ EXPECT_EQ(static_cast<size_t>(0), index);
+ return new MockUsbInterfaceDescriptor<T>(index);
+ }
+
+ protected:
+ virtual ~MockUsbConfigDescriptor() {};
+};
+
+template <class T>
+class MockUsbDevice;
+
+template <class T>
+class MockUsbDeviceHandle : public UsbDeviceHandle {
+ public:
+ explicit MockUsbDeviceHandle(MockUsbDevice<T>* device)
+ : device_(device),
+ remaining_body_length_(0),
+ next_local_socket_(0) {}
+
+ virtual scoped_refptr<UsbDevice> GetDevice() const OVERRIDE {
+ return device_;
+ }
+
+ virtual void Close() OVERRIDE { device_ = NULL; }
+
+ bool ClaimInterface(const int interface_number) {
+ if (device_->claimed_interfaces_.find(interface_number) !=
+ device_->claimed_interfaces_.end())
+ return false;
+
+ device_->claimed_interfaces_.insert(interface_number);
+ return true;
+ }
+
+ bool ReleaseInterface(const int interface_number) {
+ if (device_->claimed_interfaces_.find(interface_number) ==
+ device_->claimed_interfaces_.end())
+ return false;
+
+ device_->claimed_interfaces_.erase(interface_number);
+ return true;
+ }
+
+ virtual bool SetInterfaceAlternateSetting(
+ const int interface_number,
+ const int alternate_setting) OVERRIDE {
+ return true;
+ }
+
+ virtual bool ResetDevice() OVERRIDE { return true; }
+
+ virtual bool GetSerial(base::string16* serial) OVERRIDE {
+ *serial = base::UTF8ToUTF16(kDeviceSerial);
+ return true;
+ }
+
+ // Async IO. Can be called on any thread.
+ virtual void ControlTransfer(const UsbEndpointDirection direction,
+ const TransferRequestType request_type,
+ const TransferRecipient recipient,
+ const uint8 request,
+ const uint16 value,
+ const uint16 index,
+ net::IOBuffer* buffer,
+ const size_t length,
+ const unsigned int timeout,
+ const UsbTransferCallback& callback) OVERRIDE {}
+
+ virtual void BulkTransfer(const UsbEndpointDirection direction,
+ const uint8 endpoint,
+ net::IOBuffer* buffer,
+ const size_t length,
+ const unsigned int timeout,
+ const UsbTransferCallback& callback) OVERRIDE {
+ if (direction == USB_DIRECTION_OUTBOUND) {
+ if (remaining_body_length_ == 0) {
+ std::vector<uint32> header(6);
+ memcpy(&header[0], buffer->data(), length);
+ current_message_ = new AdbMessage(header[0], header[1], header[2], "");
+ remaining_body_length_ = header[3];
+ uint32 magic = header[5];
+ if ((current_message_->command ^ 0xffffffff) != magic) {
+ DCHECK(false) << "Header checksum error";
+ return;
+ }
+ } else {
+ DCHECK(current_message_);
+ current_message_->body += std::string(buffer->data(), length);
+ remaining_body_length_ -= length;
+ }
+
+ if (remaining_body_length_ == 0) {
+ ProcessIncoming();
+ }
+
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback,
+ usb_service::USB_TRANSFER_COMPLETED,
+ scoped_refptr<net::IOBuffer>(),
+ 0));
+
+ } else if (direction == USB_DIRECTION_INBOUND) {
+ queries_.push(Query(callback, make_scoped_refptr(buffer), length));
+ ProcessQueries();
+ }
+ }
+
+ template <class D>
+ void append(D data) {
+ std::copy(reinterpret_cast<char*>(&data),
+ (reinterpret_cast<char*>(&data)) + sizeof(D),
+ std::back_inserter(output_buffer_));
+ }
+
+ // Copied from AndroidUsbDevice::Checksum
+ uint32 Checksum(const std::string& data) {
+ unsigned char* x = (unsigned char*)data.data();
+ int count = data.length();
+ uint32 sum = 0;
+ while (count-- > 0)
+ sum += *x++;
+ return sum;
+ }
+
+ void ProcessIncoming() {
+ DCHECK(current_message_);
+ switch (current_message_->command) {
+ case AdbMessage::kCommandCNXN:
+ WriteResponse(new AdbMessage(AdbMessage::kCommandCNXN,
+ kVersion,
+ kMaxPayload,
+ "device::ro.product.name=SampleProduct;ro."
+ "product.model=SampleModel;ro.product."
+ "device=SampleDevice;"));
+ break;
+ case AdbMessage::kCommandOPEN:
+ DCHECK(current_message_->arg1 == 0);
+ DCHECK(current_message_->arg0 != 0);
+ if (current_message_->body.find("shell:") != std::string::npos) {
+ WriteResponse(new AdbMessage(AdbMessage::kCommandOKAY,
+ ++next_local_socket_,
+ current_message_->arg0,
+ ""));
+ WriteResponse(
+ new AdbMessage(AdbMessage::kCommandWRTE,
+ next_local_socket_,
+ current_message_->arg0,
+ GetMockShellResponse(current_message_->body.substr(
+ 0, current_message_->body.size() - 1))));
+ WriteResponse(new AdbMessage(
+ AdbMessage::kCommandCLSE, 0, current_message_->arg0, ""));
+ }
+ default:
+ return;
+ }
+ ProcessQueries();
+ }
+
+ void WriteResponse(scoped_refptr<AdbMessage> response) {
+ append(response->command);
+ append(response->arg0);
+ append(response->arg1);
+ bool add_zero = response->body.length() &&
+ (response->command != AdbMessage::kCommandWRTE);
+ append(static_cast<uint32>(response->body.length() + (add_zero ? 1 : 0)));
+ append(Checksum(response->body));
+ append(response->command ^ 0xffffffff);
+ std::copy(response->body.begin(),
+ response->body.end(),
+ std::back_inserter(output_buffer_));
+ if (add_zero) {
+ output_buffer_.push_back(0);
+ }
+ ProcessQueries();
+ }
+
+ void ProcessQueries() {
+ if (!queries_.size())
+ return;
+ Query query = queries_.front();
+
+ if (query.size > output_buffer_.size())
+ return;
+
+ queries_.pop();
+ std::copy(output_buffer_.begin(),
+ output_buffer_.begin() + query.size,
+ query.buffer->data());
+ output_buffer_.erase(output_buffer_.begin(),
+ output_buffer_.begin() + query.size);
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(query.callback,
+ usb_service::USB_TRANSFER_COMPLETED,
+ query.buffer,
+ query.size));
+ }
+
+ virtual void InterruptTransfer(const UsbEndpointDirection direction,
+ const uint8 endpoint,
+ net::IOBuffer* buffer,
+ const size_t length,
+ const unsigned int timeout,
+ const UsbTransferCallback& callback) OVERRIDE {
+ }
+
+ virtual void IsochronousTransfer(
+ const UsbEndpointDirection direction,
+ const uint8 endpoint,
+ net::IOBuffer* buffer,
+ const size_t length,
+ const unsigned int packets,
+ const unsigned int packet_length,
+ const unsigned int timeout,
+ const UsbTransferCallback& callback) OVERRIDE {}
+
+ protected:
+ virtual ~MockUsbDeviceHandle() {}
+
+ struct Query {
+ UsbTransferCallback callback;
+ scoped_refptr<net::IOBuffer> buffer;
+ size_t size;
+
+ Query(UsbTransferCallback callback,
+ scoped_refptr<net::IOBuffer> buffer,
+ int size)
+ : callback(callback), buffer(buffer), size(size) {};
+ };
+
+ scoped_refptr<MockUsbDevice<T> > device_;
+ uint32 remaining_body_length_;
+ scoped_refptr<AdbMessage> current_message_;
+ std::vector<char> output_buffer_;
+ std::queue<Query> queries_;
+ int next_local_socket_;
+};
+
+template <class T>
+class MockUsbDevice : public UsbDevice {
+ public:
+ MockUsbDevice() : UsbDevice(0, 0, 0) {}
+
+ virtual scoped_refptr<UsbDeviceHandle> Open() OVERRIDE {
+ return new MockUsbDeviceHandle<T>(this);
+ }
+
+ virtual scoped_refptr<UsbConfigDescriptor> ListInterfaces() OVERRIDE {
+ return new MockUsbConfigDescriptor<T>();
+ }
+
+ virtual bool Close(scoped_refptr<UsbDeviceHandle> handle) OVERRIDE {
+ return true;
+ }
+
+#if defined(OS_CHROMEOS)
+ // On ChromeOS, if an interface of a claimed device is not claimed, the
+ // permission broker can change the owner of the device so that the unclaimed
+ // interfaces can be used. If this argument is missing, permission broker will
+ // not be used and this method fails if the device is claimed.
+ virtual void RequestUsbAcess(
+ int interface_id,
+ const base::Callback<void(bool success)>& callback) OVERRIDE {
+ callback.Run(true);
+ }
+#endif // OS_CHROMEOS
+
+ std::set<int> claimed_interfaces_;
+
+ protected:
+ virtual ~MockUsbDevice() {}
+};
+
+class MockUsbService : public UsbService {
+ public:
+ MockUsbService() {
+ devices_.push_back(new MockUsbDevice<AndroidTraits>());
+ }
+
+ virtual ~MockUsbService() {}
+
+ virtual scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) OVERRIDE {
+ NOTIMPLEMENTED();
+ return NULL;
+ }
+
+ virtual void GetDevices(
+ std::vector<scoped_refptr<UsbDevice> >* devices) OVERRIDE {
+ STLClearObject(devices);
+ std::copy(devices_.begin(), devices_.end(), back_inserter(*devices));
+ }
+
+ std::vector<scoped_refptr<UsbDevice> > devices_;
+};
+
+class MockUsbServiceForCheckingTraits : public UsbService {
+ public:
+ MockUsbServiceForCheckingTraits() : step_(0) {}
+
+ virtual ~MockUsbServiceForCheckingTraits() {}
+
+ virtual scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) OVERRIDE {
+ NOTIMPLEMENTED();
+ return NULL;
+ }
+
+ virtual void GetDevices(
+ std::vector<scoped_refptr<UsbDevice> >* devices) OVERRIDE {
+ STLClearObject(devices);
+ // This switch should be kept in sync with
+ // AndroidUsbBrowserTest::DeviceCountChanged.
+ switch (step_) {
+ case 0:
+ // No devices.
+ break;
+ case 1:
+ // Android device.
+ devices->push_back(new MockUsbDevice<AndroidTraits>());
+ break;
+ case 2:
+ // Android and non-android device.
+ devices->push_back(new MockUsbDevice<AndroidTraits>());
+ devices->push_back(new MockUsbDevice<NonAndroidTraits>());
+ break;
+ case 3:
+ // Non-android device.
+ devices->push_back(new MockUsbDevice<NonAndroidTraits>());
+ break;
+ }
+ step_++;
+ }
+
+ private:
+ int step_;
+};
+
+class DevToolsAndroidBridgeWarmUp
+ : public DevToolsAndroidBridge::DeviceCountListener {
+ public:
+ DevToolsAndroidBridgeWarmUp(base::Closure closure,
+ scoped_refptr<DevToolsAndroidBridge> adb_bridge)
+ : closure_(closure), adb_bridge_(adb_bridge) {}
+
+ virtual void DeviceCountChanged(int count) OVERRIDE {
+ adb_bridge_->RemoveDeviceCountListener(this);
+ closure_.Run();
+ }
+
+ base::Closure closure_;
+ scoped_refptr<DevToolsAndroidBridge> adb_bridge_;
+};
+
+class AndroidUsbDiscoveryTest : public InProcessBrowserTest {
+ protected:
+ AndroidUsbDiscoveryTest()
+ : scheduler_invoked_(0) {
+ }
+ virtual void SetUpOnMainThread() OVERRIDE {
+ scoped_refptr<content::MessageLoopRunner> runner =
+ new content::MessageLoopRunner;
+
+ BrowserThread::PostTaskAndReply(
+ BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&AndroidUsbDiscoveryTest::SetUpService, this),
+ runner->QuitClosure());
+ runner->Run();
+
+ adb_bridge_ =
+ DevToolsAndroidBridge::Factory::GetForProfile(browser()->profile());
+ DCHECK(adb_bridge_);
+ adb_bridge_->set_task_scheduler_for_test(base::Bind(
+ &AndroidUsbDiscoveryTest::ScheduleDeviceCountRequest, this));
+
+ scoped_refptr<UsbDeviceProvider> provider =
+ new UsbDeviceProvider(browser()->profile());
+
+ AndroidDeviceManager::DeviceProviders providers;
+ providers.push_back(provider);
+ adb_bridge_->set_device_providers_for_test(providers);
+ runner_ = new content::MessageLoopRunner;
+ }
+
+ void ScheduleDeviceCountRequest(const base::Closure& request) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ scheduler_invoked_++;
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, request);
+ }
+
+ virtual void SetUpService() {
+ UsbService::SetInstanceForTest(new MockUsbService());
+ }
+
+ virtual void CleanUpOnMainThread() OVERRIDE {
+ scoped_refptr<content::MessageLoopRunner> runner =
+ new content::MessageLoopRunner;
+ UsbService* service = NULL;
+ BrowserThread::PostTaskAndReply(
+ BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&UsbService::SetInstanceForTest, service),
+ runner->QuitClosure());
+ runner->Run();
+ }
+
+ scoped_refptr<content::MessageLoopRunner> runner_;
+ scoped_refptr<DevToolsAndroidBridge> adb_bridge_;
+ int scheduler_invoked_;
+};
+
+class AndroidUsbCountTest : public AndroidUsbDiscoveryTest {
+ protected:
+ virtual void SetUpOnMainThread() OVERRIDE {
+ AndroidUsbDiscoveryTest::SetUpOnMainThread();
+ DevToolsAndroidBridgeWarmUp warmup(runner_->QuitClosure(), adb_bridge_);
+ adb_bridge_->AddDeviceCountListener(&warmup);
+ runner_->Run();
+ runner_ = new content::MessageLoopRunner;
+ }
+};
+
+class AndroidUsbTraitsTest : public AndroidUsbDiscoveryTest {
+ protected:
+ virtual void SetUpService() {
+ UsbService::SetInstanceForTest(new MockUsbServiceForCheckingTraits());
+ }
+};
+
+class MockListListener : public DevToolsAndroidBridge::DeviceListListener {
+ public:
+ MockListListener(scoped_refptr<DevToolsAndroidBridge> adb_bridge,
+ const base::Closure& callback)
+ : adb_bridge_(adb_bridge),
+ callback_(callback) {
+ }
+ virtual void DeviceListChanged(
+ const DevToolsAndroidBridge::RemoteDevices& devices) OVERRIDE {
+ if (devices.size() > 0) {
+ if (devices[0]->is_connected()) {
+ ASSERT_EQ(kDeviceModel, devices[0]->model());
+ ASSERT_EQ(kDeviceSerial, devices[0]->serial());
+ adb_bridge_->RemoveDeviceListListener(this);
+ callback_.Run();
+ }
+ }
+ }
+
+ scoped_refptr<DevToolsAndroidBridge> adb_bridge_;
+ base::Closure callback_;
+};
+
+class MockCountListener : public DevToolsAndroidBridge::DeviceCountListener {
+ public:
+ explicit MockCountListener(scoped_refptr<DevToolsAndroidBridge> adb_bridge)
+ : adb_bridge_(adb_bridge),
+ reposts_left_(10),
+ invoked_(0) {
+ }
+
+ virtual void DeviceCountChanged(int count) OVERRIDE {
+ ++invoked_;
+ adb_bridge_->RemoveDeviceCountListener(this);
+ Shutdown();
+ }
+
+ void Shutdown() {
+ ShutdownOnUIThread();
+ };
+
+ void ShutdownOnUIThread() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (reposts_left_-- == 0) {
+ base::MessageLoop::current()->Quit();
+ } else {
+ BrowserThread::PostTask(
+ BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&MockCountListener::ShutdownOnFileThread,
+ base::Unretained(this)));
+ }
+ }
+
+ void ShutdownOnFileThread() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&MockCountListener::ShutdownOnUIThread,
+ base::Unretained(this)));
+ }
+
+ scoped_refptr<DevToolsAndroidBridge> adb_bridge_;
+ int reposts_left_;
+ int invoked_;
+};
+
+class MockCountListenerWithReAdd : public MockCountListener {
+ public:
+ explicit MockCountListenerWithReAdd(
+ scoped_refptr<DevToolsAndroidBridge> adb_bridge)
+ : MockCountListener(adb_bridge),
+ readd_count_(2) {
+ }
+
+ virtual void DeviceCountChanged(int count) OVERRIDE {
+ ++invoked_;
+ adb_bridge_->RemoveDeviceCountListener(this);
+ if (readd_count_ > 0) {
+ readd_count_--;
+ adb_bridge_->AddDeviceCountListener(this);
+ adb_bridge_->RemoveDeviceCountListener(this);
+ adb_bridge_->AddDeviceCountListener(this);
+ } else {
+ Shutdown();
+ }
+ }
+
+ int readd_count_;
+};
+
+class MockCountListenerWithReAddWhileQueued : public MockCountListener {
+ public:
+ MockCountListenerWithReAddWhileQueued(
+ scoped_refptr<DevToolsAndroidBridge> adb_bridge)
+ : MockCountListener(adb_bridge),
+ readded_(false) {
+ }
+
+ virtual void DeviceCountChanged(int count) OVERRIDE {
+ ++invoked_;
+ if (!readded_) {
+ readded_ = true;
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&MockCountListenerWithReAddWhileQueued::ReAdd,
+ base::Unretained(this)));
+ } else {
+ adb_bridge_->RemoveDeviceCountListener(this);
+ Shutdown();
+ }
+ }
+
+ void ReAdd() {
+ adb_bridge_->RemoveDeviceCountListener(this);
+ adb_bridge_->AddDeviceCountListener(this);
+ }
+
+ bool readded_;
+};
+
+class MockCountListenerForCheckingTraits : public MockCountListener {
+ public:
+ MockCountListenerForCheckingTraits(
+ scoped_refptr<DevToolsAndroidBridge> adb_bridge)
+ : MockCountListener(adb_bridge),
+ step_(0) {
+ }
+ virtual void DeviceCountChanged(int count) OVERRIDE {
+ switch (step_) {
+ case 0:
+ // Check for 0 devices when no devices present.
+ EXPECT_EQ(0, count);
+ break;
+ case 1:
+ // Check for 1 device when only android device present.
+ EXPECT_EQ(1, count);
+ break;
+ case 2:
+ // Check for 1 device when android and non-android devices present.
+ EXPECT_EQ(1, count);
+ break;
+ case 3:
+ // Check for 0 devices when only non-android devices present.
+ EXPECT_EQ(0, count);
+ adb_bridge_->RemoveDeviceCountListener(this);
+ Shutdown();
+ break;
+ default:
+ EXPECT_TRUE(false) << "Unknown step " << step_;
+ }
+ step_++;
+ }
+
+ int step_;
+};
+
+} // namespace
+
+IN_PROC_BROWSER_TEST_F(AndroidUsbDiscoveryTest, TestDeviceDiscovery) {
+ scoped_ptr<MockListListener> listener(
+ new MockListListener(adb_bridge_, runner_->QuitClosure()));
+ adb_bridge_->AddDeviceListListener(listener.get());
+ runner_->Run();
+}
+
+IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
+ TestNoMultipleCallsRemoveInCallback) {
+ scoped_ptr<MockCountListener> listener(new MockCountListener(adb_bridge_));
Vladislav Kaznacheev 2014/06/17 10:27:16 Is there a reason you are using scoped_ptr instead
vkuzkokov 2014/06/17 13:01:44 No reason. Moved to stack.
+
+ adb_bridge_->AddDeviceCountListener(listener.get());
+
+ runner_->Run();
+ EXPECT_EQ(1, listener->invoked_);
+ EXPECT_EQ(listener->invoked_ - 1, scheduler_invoked_);
+}
+
+IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
+ TestNoMultipleCallsRemoveAddInCallback) {
+ scoped_ptr<MockCountListener> listener(
+ new MockCountListenerWithReAdd(adb_bridge_));
+
+ adb_bridge_->AddDeviceCountListener(listener.get());
+
+ runner_->Run();
+ EXPECT_EQ(3, listener->invoked_);
+ EXPECT_EQ(listener->invoked_ - 1, scheduler_invoked_);
+}
+
+IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
+ TestNoMultipleCallsRemoveAddOnStart) {
+ scoped_ptr<MockCountListener> listener(new MockCountListener(adb_bridge_));
+
+ adb_bridge_->AddDeviceCountListener(listener.get());
+ adb_bridge_->RemoveDeviceCountListener(listener.get());
+ adb_bridge_->AddDeviceCountListener(listener.get());
+
+ runner_->Run();
+ EXPECT_EQ(1, listener->invoked_);
+ EXPECT_EQ(listener->invoked_ - 1, scheduler_invoked_);
+}
+
+IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
+ TestNoMultipleCallsRemoveAddWhileQueued) {
+ scoped_ptr<MockCountListener> listener(
+ new MockCountListenerWithReAddWhileQueued(adb_bridge_));
+
+ adb_bridge_->AddDeviceCountListener(listener.get());
+
+ runner_->Run();
+ EXPECT_EQ(2, listener->invoked_);
+ EXPECT_EQ(listener->invoked_ - 1, scheduler_invoked_);
+}
+
+IN_PROC_BROWSER_TEST_F(AndroidUsbTraitsTest, TestDeviceCounting) {
+ scoped_ptr<MockCountListener> listener(
+ new MockCountListenerForCheckingTraits(adb_bridge_));
+
+ adb_bridge_->AddDeviceCountListener(listener.get());
+ runner_->Run();
+}
« no previous file with comments | « no previous file | chrome/browser/devtools/device/usb/devtools_android_bridge_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698