CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
299 lines
11 KiB
C++
299 lines
11 KiB
C++
//===-- PlatformAndroidTest.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/PlatformAndroid.h"
|
|
#include "Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h"
|
|
#include "lldb/Utility/Connection.h"
|
|
#include "gmock/gmock.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
using namespace lldb_private::platform_android;
|
|
using namespace testing;
|
|
|
|
namespace {
|
|
|
|
class MockAdbClient : public AdbClient {
|
|
public:
|
|
explicit MockAdbClient() : AdbClient() {}
|
|
|
|
MOCK_METHOD3(ShellToFile,
|
|
Status(const char *command, std::chrono::milliseconds timeout,
|
|
const FileSpec &output_file_spec));
|
|
};
|
|
|
|
class PlatformAndroidTest : public PlatformAndroid, public ::testing::Test {
|
|
public:
|
|
PlatformAndroidTest() : PlatformAndroid(false) {
|
|
m_remote_platform_sp = PlatformSP(new PlatformAndroidRemoteGDBServer());
|
|
|
|
// Set up default mock behavior to avoid uninteresting call warnings
|
|
ON_CALL(*this, GetSyncService(_))
|
|
.WillByDefault([](Status &error) -> std::unique_ptr<AdbSyncService> {
|
|
error = Status::FromErrorString("Sync service unavailable");
|
|
return nullptr;
|
|
});
|
|
}
|
|
|
|
MOCK_METHOD1(GetAdbClient, AdbClientUP(Status &error));
|
|
MOCK_METHOD0(GetPropertyPackageName, llvm::StringRef());
|
|
MOCK_METHOD1(GetSyncService, std::unique_ptr<AdbSyncService>(Status &error));
|
|
|
|
// Make GetSyncService public for testing
|
|
using PlatformAndroid::GetSyncService;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
TEST_F(PlatformAndroidTest,
|
|
DownloadModuleSlice_AdbClientError_FailsGracefully) {
|
|
EXPECT_CALL(*this, GetAdbClient(_))
|
|
.WillOnce(DoAll(WithArg<0>([](auto &arg) {
|
|
arg = Status::FromErrorString(
|
|
"Failed to create AdbClient");
|
|
}),
|
|
Return(ByMove(AdbClientUP()))));
|
|
|
|
Status result = DownloadModuleSlice(
|
|
FileSpec("/system/app/Test/Test.apk!/lib/arm64-v8a/libtest.so"), 4096,
|
|
3600, FileSpec("/tmp/libtest.so"));
|
|
|
|
EXPECT_TRUE(result.Fail());
|
|
EXPECT_THAT(result.AsCString(), HasSubstr("Failed to create AdbClient"));
|
|
}
|
|
|
|
TEST_F(PlatformAndroidTest, DownloadModuleSlice_ZipFile_UsesCorrectDdCommand) {
|
|
auto *adb_client = new MockAdbClient();
|
|
EXPECT_CALL(*adb_client,
|
|
ShellToFile(StrEq("dd if='/system/app/Test/Test.apk' "
|
|
"iflag=skip_bytes,count_bytes "
|
|
"skip=4096 count=3600 status=none"),
|
|
_, _))
|
|
.WillOnce(Return(Status()));
|
|
|
|
EXPECT_CALL(*this, GetPropertyPackageName())
|
|
.WillOnce(Return(llvm::StringRef("")));
|
|
|
|
EXPECT_CALL(*this, GetAdbClient(_))
|
|
.WillOnce(Return(ByMove(AdbClientUP(adb_client))));
|
|
|
|
Status result = DownloadModuleSlice(
|
|
FileSpec("/system/app/Test/Test.apk!/lib/arm64-v8a/libtest.so"), 4096,
|
|
3600, FileSpec("/tmp/libtest.so"));
|
|
|
|
EXPECT_TRUE(result.Success());
|
|
}
|
|
|
|
TEST_F(PlatformAndroidTest,
|
|
DownloadModuleSlice_ZipFileWithRunAs_UsesRunAsCommand) {
|
|
auto *adb_client = new MockAdbClient();
|
|
EXPECT_CALL(*adb_client,
|
|
ShellToFile(StrEq("run-as 'com.example.test' "
|
|
"dd if='/system/app/Test/Test.apk' "
|
|
"iflag=skip_bytes,count_bytes "
|
|
"skip=4096 count=3600 status=none"),
|
|
_, _))
|
|
.WillOnce(Return(Status()));
|
|
|
|
EXPECT_CALL(*this, GetPropertyPackageName())
|
|
.WillOnce(Return(llvm::StringRef("com.example.test")));
|
|
|
|
EXPECT_CALL(*this, GetAdbClient(_))
|
|
.WillOnce(Return(ByMove(AdbClientUP(adb_client))));
|
|
|
|
Status result = DownloadModuleSlice(
|
|
FileSpec("/system/app/Test/Test.apk!/lib/arm64-v8a/libtest.so"), 4096,
|
|
3600, FileSpec("/tmp/libtest.so"));
|
|
|
|
EXPECT_TRUE(result.Success());
|
|
}
|
|
|
|
TEST_F(PlatformAndroidTest,
|
|
DownloadModuleSlice_LargeFile_CalculatesParametersCorrectly) {
|
|
const uint64_t large_offset = 100 * 1024 * 1024; // 100MB offset
|
|
const uint64_t large_size = 50 * 1024 * 1024; // 50MB size
|
|
|
|
auto *adb_client = new MockAdbClient();
|
|
EXPECT_CALL(*adb_client,
|
|
ShellToFile(StrEq("dd if='/system/app/Large.apk' "
|
|
"iflag=skip_bytes,count_bytes "
|
|
"skip=104857600 count=52428800 status=none"),
|
|
_, _))
|
|
.WillOnce(Return(Status()));
|
|
|
|
EXPECT_CALL(*this, GetPropertyPackageName())
|
|
.WillOnce(Return(llvm::StringRef("")));
|
|
|
|
EXPECT_CALL(*this, GetAdbClient(_))
|
|
.WillOnce(Return(ByMove(AdbClientUP(adb_client))));
|
|
|
|
Status result = DownloadModuleSlice(
|
|
FileSpec("/system/app/Large.apk!/lib/arm64-v8a/large.so"), large_offset,
|
|
large_size, FileSpec("/tmp/large.so"));
|
|
|
|
EXPECT_TRUE(result.Success());
|
|
}
|
|
|
|
TEST_F(PlatformAndroidTest,
|
|
GetFile_SyncServiceUnavailable_FallsBackToShellCat) {
|
|
auto *adb_client = new MockAdbClient();
|
|
EXPECT_CALL(*adb_client,
|
|
ShellToFile(StrEq("cat '/data/local/tmp/test'"), _, _))
|
|
.WillOnce(Return(Status()));
|
|
|
|
EXPECT_CALL(*this, GetPropertyPackageName())
|
|
.WillOnce(Return(llvm::StringRef("")));
|
|
|
|
EXPECT_CALL(*this, GetAdbClient(_))
|
|
.WillOnce(DoAll(WithArg<0>([](auto &arg) { arg.Clear(); }),
|
|
Return(ByMove(AdbClientUP(adb_client)))));
|
|
|
|
EXPECT_CALL(*this, GetSyncService(_))
|
|
.WillOnce([](Status &error) -> std::unique_ptr<AdbSyncService> {
|
|
error = Status::FromErrorString("Sync service unavailable");
|
|
return nullptr;
|
|
});
|
|
|
|
Status result =
|
|
GetFile(FileSpec("/data/local/tmp/test"), FileSpec("/tmp/test"));
|
|
EXPECT_TRUE(result.Success());
|
|
}
|
|
|
|
TEST_F(PlatformAndroidTest, GetFile_WithRunAs_UsesRunAsInShellCommand) {
|
|
auto *adb_client = new MockAdbClient();
|
|
EXPECT_CALL(
|
|
*adb_client,
|
|
ShellToFile(StrEq("run-as 'com.example.app' "
|
|
"cat '/data/data/com.example.app/lib-main/libtest.so'"),
|
|
_, _))
|
|
.WillOnce(Return(Status()));
|
|
|
|
EXPECT_CALL(*this, GetPropertyPackageName())
|
|
.WillOnce(Return(llvm::StringRef("com.example.app")));
|
|
|
|
EXPECT_CALL(*this, GetAdbClient(_))
|
|
.WillOnce(DoAll(WithArg<0>([](auto &arg) { arg.Clear(); }),
|
|
Return(ByMove(AdbClientUP(adb_client)))));
|
|
|
|
EXPECT_CALL(*this, GetSyncService(_))
|
|
.WillOnce([](Status &error) -> std::unique_ptr<AdbSyncService> {
|
|
error = Status::FromErrorString("Sync service unavailable");
|
|
return nullptr;
|
|
});
|
|
|
|
Status result =
|
|
GetFile(FileSpec("/data/data/com.example.app/lib-main/libtest.so"),
|
|
FileSpec("/tmp/libtest.so"));
|
|
EXPECT_TRUE(result.Success());
|
|
}
|
|
|
|
TEST_F(PlatformAndroidTest, GetFile_FilenameWithSingleQuotes_Rejected) {
|
|
EXPECT_CALL(*this, GetSyncService(_))
|
|
.WillOnce([](Status &error) -> std::unique_ptr<AdbSyncService> {
|
|
error = Status::FromErrorString("Sync service unavailable");
|
|
return nullptr;
|
|
});
|
|
|
|
Status result =
|
|
GetFile(FileSpec("/test/file'with'quotes"), FileSpec("/tmp/output"));
|
|
|
|
EXPECT_TRUE(result.Fail());
|
|
EXPECT_THAT(result.AsCString(), HasSubstr("single-quotes"));
|
|
}
|
|
|
|
TEST_F(PlatformAndroidTest,
|
|
DownloadModuleSlice_FilenameWithSingleQuotes_Rejected) {
|
|
Status result = DownloadModuleSlice(FileSpec("/test/file'with'quotes"), 100,
|
|
200, FileSpec("/tmp/output"));
|
|
|
|
EXPECT_TRUE(result.Fail());
|
|
EXPECT_THAT(result.AsCString(), HasSubstr("single-quotes"));
|
|
}
|
|
|
|
TEST_F(PlatformAndroidTest, GetFile_NetworkTimeout_PropagatesErrorCorrectly) {
|
|
auto *adb_client = new MockAdbClient();
|
|
EXPECT_CALL(*adb_client, ShellToFile(_, _, _))
|
|
.WillOnce(Return(Status::FromErrorString("Network timeout")));
|
|
|
|
EXPECT_CALL(*this, GetPropertyPackageName())
|
|
.WillOnce(Return(llvm::StringRef("")));
|
|
|
|
EXPECT_CALL(*this, GetAdbClient(_))
|
|
.WillOnce(DoAll(WithArg<0>([](auto &arg) { arg.Clear(); }),
|
|
Return(ByMove(AdbClientUP(adb_client)))));
|
|
|
|
EXPECT_CALL(*this, GetSyncService(_))
|
|
.WillOnce([](Status &error) -> std::unique_ptr<AdbSyncService> {
|
|
error = Status::FromErrorString("Sync service unavailable");
|
|
return nullptr;
|
|
});
|
|
|
|
Status result =
|
|
GetFile(FileSpec("/data/large/file.so"), FileSpec("/tmp/large.so"));
|
|
EXPECT_TRUE(result.Fail());
|
|
EXPECT_THAT(result.AsCString(), HasSubstr("Network timeout"));
|
|
}
|
|
|
|
TEST_F(PlatformAndroidTest, SyncService_ConnectionFailsGracefully) {
|
|
// Constructor should succeed even with a failing connection
|
|
AdbSyncService sync_service("test-device");
|
|
|
|
// The service should report as not connected initially
|
|
EXPECT_FALSE(sync_service.IsConnected());
|
|
EXPECT_EQ(sync_service.GetDeviceId(), "test-device");
|
|
|
|
// Operations should fail gracefully when connection setup fails
|
|
FileSpec remote_file("/data/test.txt");
|
|
FileSpec local_file("/tmp/test.txt");
|
|
uint32_t mode, size, mtime;
|
|
|
|
Status result = sync_service.Stat(remote_file, mode, size, mtime);
|
|
EXPECT_TRUE(result.Fail());
|
|
}
|
|
|
|
TEST_F(PlatformAndroidTest, GetRunAs_FormatsPackageNameCorrectly) {
|
|
// Empty package name
|
|
EXPECT_CALL(*this, GetPropertyPackageName())
|
|
.WillOnce(Return(llvm::StringRef("")));
|
|
EXPECT_EQ(this->GetRunAs(), "");
|
|
|
|
// Valid package name
|
|
EXPECT_CALL(*this, GetPropertyPackageName())
|
|
.WillOnce(Return(llvm::StringRef("com.example.test")));
|
|
EXPECT_EQ(this->GetRunAs(), "run-as 'com.example.test' ");
|
|
}
|
|
|
|
TEST_F(PlatformAndroidTest,
|
|
DownloadModuleSlice_ZeroOffset_CallsGetFileInsteadOfDd) {
|
|
// When offset=0, DownloadModuleSlice calls GetFile which uses 'cat', not 'dd'
|
|
// We need to ensure the sync service fails so GetFile falls back to shell cat
|
|
auto *adb_client = new MockAdbClient();
|
|
EXPECT_CALL(*adb_client,
|
|
ShellToFile(StrEq("cat '/system/lib64/libc.so'"), _, _))
|
|
.WillOnce(Return(Status()));
|
|
|
|
EXPECT_CALL(*this, GetPropertyPackageName())
|
|
.WillOnce(Return(llvm::StringRef("")));
|
|
|
|
EXPECT_CALL(*this, GetAdbClient(_))
|
|
.WillOnce(DoAll(WithArg<0>([](auto &arg) { arg.Clear(); }),
|
|
Return(ByMove(AdbClientUP(adb_client)))));
|
|
|
|
// Mock GetSyncService to fail, forcing GetFile to use shell cat fallback
|
|
EXPECT_CALL(*this, GetSyncService(_))
|
|
.WillOnce(DoAll(WithArg<0>([](auto &arg) {
|
|
arg =
|
|
Status::FromErrorString("Sync service unavailable");
|
|
}),
|
|
Return(ByMove(std::unique_ptr<AdbSyncService>()))));
|
|
|
|
Status result = DownloadModuleSlice(FileSpec("/system/lib64/libc.so"), 0, 0,
|
|
FileSpec("/tmp/libc.so"));
|
|
EXPECT_TRUE(result.Success());
|
|
}
|