1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
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
135
136
137
138
139
140
141
142
143
|
//===-- AdbClientTest.cpp -------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "Plugins/Platform/Android/AdbClient.h"
#include "lldb/Host/Socket.h"
#include "lldb/Host/common/TCPSocket.h"
#include "gtest/gtest.h"
#include <chrono>
#include <cstdlib>
static void set_env(const char *var, const char *value) {
#ifdef _WIN32
_putenv_s(var, value);
#else
setenv(var, value, true);
#endif
}
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::platform_android;
class AdbClientTest : public ::testing::Test {
public:
void SetUp() override {
set_env("ANDROID_SERIAL", "");
set_env("ANDROID_ADB_SERVER_PORT", "");
}
void TearDown() override {
set_env("ANDROID_SERIAL", "");
set_env("ANDROID_ADB_SERVER_PORT", "");
}
};
TEST_F(AdbClientTest, ResolveDeviceId_ExplicitDeviceId) {
auto result = AdbClient::ResolveDeviceID("device1");
EXPECT_TRUE(static_cast<bool>(result));
EXPECT_EQ("device1", *result);
}
TEST_F(AdbClientTest, ResolveDeviceId_ByEnvVar) {
set_env("ANDROID_SERIAL", "device2");
auto result = AdbClient::ResolveDeviceID("");
EXPECT_TRUE(static_cast<bool>(result));
EXPECT_EQ("device2", *result);
}
TEST_F(AdbClientTest, ResolveDeviceId_PrefersExplicitOverEnvVar) {
set_env("ANDROID_SERIAL", "env_device");
// Explicit device ID should take precedence over environment variable
auto result = AdbClient::ResolveDeviceID("explicit_device");
EXPECT_TRUE(static_cast<bool>(result));
EXPECT_EQ("explicit_device", *result);
}
TEST_F(AdbClientTest, AdbClient_Constructor_StoresDeviceId) {
AdbClient client("test_device_123");
EXPECT_EQ(client.GetDeviceID(), "test_device_123");
}
TEST_F(AdbClientTest, AdbClient_DefaultConstructor) {
AdbClient client;
EXPECT_EQ(client.GetDeviceID(), "");
}
TEST_F(AdbClientTest, AdbSyncService_Constructor_StoresDeviceId) {
AdbSyncService sync("device123");
EXPECT_EQ(sync.GetDeviceId(), "device123");
}
TEST_F(AdbClientTest, AdbSyncService_OperationsFailWhenNotConnected) {
AdbSyncService sync_service("test_device");
// Verify service is not connected initially
EXPECT_FALSE(sync_service.IsConnected());
// File operations should fail when not connected
FileSpec remote_file("/data/test.txt");
FileSpec local_file("/tmp/test.txt");
uint32_t mode, size, mtime;
Status stat_result = sync_service.Stat(remote_file, mode, size, mtime);
EXPECT_TRUE(stat_result.Fail());
Status pull_result = sync_service.PullFile(remote_file, local_file);
EXPECT_TRUE(pull_result.Fail());
Status push_result = sync_service.PushFile(local_file, remote_file);
EXPECT_TRUE(push_result.Fail());
}
static uint16_t FindUnusedPort() {
auto temp_socket = std::make_unique<TCPSocket>(true);
Status error = temp_socket->Listen("localhost:0", 1);
if (error.Fail()) {
return 0; // fallback
}
uint16_t port = temp_socket->GetLocalPortNumber();
temp_socket.reset(); // Close the socket to free the port
return port;
}
#ifndef _WIN32
// This test is disabled on Windows due to platform-specific socket behavior
// that causes assertion failures in TCPSocket::Listen()
TEST_F(AdbClientTest, RealTcpConnection) {
uint16_t unused_port = FindUnusedPort();
ASSERT_NE(unused_port, 0) << "Failed to find an unused port";
std::string port_str = std::to_string(unused_port);
set_env("ANDROID_ADB_SERVER_PORT", port_str.c_str());
AdbClient client;
const auto status1 = client.Connect();
EXPECT_FALSE(status1.Success())
<< "Connection should fail when no server is listening on port "
<< unused_port;
// now start a server on the port and try again
auto listen_socket = std::make_unique<TCPSocket>(true);
std::string listen_address = "localhost:" + port_str;
Status error = listen_socket->Listen(listen_address.c_str(), 5);
ASSERT_TRUE(error.Success()) << "Failed to create listening socket on port "
<< unused_port << ": " << error.AsCString();
// Verify the socket is listening on the expected port
ASSERT_EQ(listen_socket->GetLocalPortNumber(), unused_port)
<< "Socket is not listening on the expected port";
const auto status2 = client.Connect();
EXPECT_TRUE(status2.Success())
<< "Connection should succeed when server is listening on port "
<< unused_port;
}
#endif // _WIN32
|