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

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

Issue 291193007: Added android usb device discovery test via mocked usb service. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 7 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/chrome_tests.gypi » ('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_discovery_test.cc
diff --git a/chrome/browser/devtools/device/usb/android_usb_discovery_test.cc b/chrome/browser/devtools/device/usb/android_usb_discovery_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..0c8f07b655e861c761fb182db5fe80fd336311c7
--- /dev/null
+++ b/chrome/browser/devtools/device/usb/android_usb_discovery_test.cc
@@ -0,0 +1,558 @@
+// Copyright (c) 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 {
+const int kClass = 0xff;
+const int kSubclass = 0x42;
+const int kProtocol = 0x1;
+
+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() {}
+};
+
+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 kClass; }
+
+ virtual int GetInterfaceSubclass() const OVERRIDE { return kSubclass; }
+
+ virtual int GetInterfaceProtocol() const OVERRIDE { return kProtocol; }
+
+ protected:
+ virtual ~MockUsbInterfaceAltSettingDescriptor() {};
+
+ private:
+ const int interface_number_;
+ const int alternate_setting_;
+};
+
+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(interface_number_, 0);
+ }
+
+ protected:
+ const int interface_number_;
+ virtual ~MockUsbInterfaceDescriptor() {}
+};
+
+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(index);
+ }
+
+ protected:
+ virtual ~MockUsbConfigDescriptor() {};
+};
+
+class MockUsbDevice;
+
+class MockUsbDeviceHandle : public UsbDeviceHandle {
+ public:
+ explicit MockUsbDeviceHandle(MockUsbDevice* device)
+ : device_(device), remaining_body_length_(0) {}
+
+ virtual scoped_refptr<UsbDevice> GetDevice() const OVERRIDE {
+ return device_;
+ }
+
+ virtual void Close() OVERRIDE { device_ = NULL; }
+
+ virtual bool ClaimInterface(const int interface_number) OVERRIDE;
+ virtual bool ReleaseInterface(const int interface_number) OVERRIDE;
+ 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 T>
+ void append(T data) {
+ std::copy(reinterpret_cast<char*>(&data),
+ (reinterpret_cast<char*>(&data)) + sizeof(T),
+ 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> device_;
+ uint32 remaining_body_length_;
+ scoped_refptr<AdbMessage> current_message_;
+ std::vector<char> output_buffer_;
+ std::queue<Query> queries_;
+ int next_local_socket_ = 1;
+};
+
+class MockUsbDevice : public UsbDevice {
+ public:
+ MockUsbDevice() : UsbDevice(0, 0, 0) {}
+
+ virtual scoped_refptr<UsbDeviceHandle> Open() OVERRIDE {
+ return new MockUsbDeviceHandle(this);
+ }
+
+ virtual scoped_refptr<UsbConfigDescriptor> ListInterfaces() OVERRIDE {
+ return new MockUsbConfigDescriptor();
+ }
+
+ 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()); }
+
+ 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_;
+};
+
+bool MockUsbDeviceHandle::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 MockUsbDeviceHandle::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;
+}
+
+class AndroidUsbDiscoveryTest
+ : public InProcessBrowserTest,
+ public DevToolsAndroidBridge::DeviceListListener {
+ protected:
+ 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());
+
+ 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 SetUpService() {
+ service_ = new MockUsbService();
+ UsbService::SetInstanceForTest(service_);
+ }
+
+ 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();
+ }
+
+ 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);
+ runner_->Quit();
+ }
+ }
+ }
+
+ bool passed = false;
+ scoped_refptr<content::MessageLoopRunner> runner_;
+ MockUsbService* service_;
+ scoped_refptr<DevToolsAndroidBridge> adb_bridge_;
+};
+
+} // namespace
+
+IN_PROC_BROWSER_TEST_F(AndroidUsbDiscoveryTest, TestDeviceDiscovery) {
+ if (!adb_bridge_) {
+ FAIL() << "Failed to get DevToolsAndroidBridge.";
+ }
+
+ adb_bridge_->AddDeviceListListener(this);
+
+ runner_->Run();
+}
« no previous file with comments | « no previous file | chrome/chrome_tests.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698