Index: lldb/trunk/unittests/Utility/CMakeLists.txt =================================================================== --- lldb/trunk/unittests/Utility/CMakeLists.txt +++ lldb/trunk/unittests/Utility/CMakeLists.txt @@ -1,5 +1,8 @@ add_lldb_unittest(UtilityTests + ModuleCacheTest.cpp StringExtractorTest.cpp TaskPoolTest.cpp UriParserTest.cpp ) + +add_unittest_inputs(UtilityTests TestModule.so) Index: lldb/trunk/unittests/Utility/Inputs/TestModule.c =================================================================== --- lldb/trunk/unittests/Utility/Inputs/TestModule.c +++ lldb/trunk/unittests/Utility/Inputs/TestModule.c @@ -0,0 +1,10 @@ +// Compile with $CC -nostdlib -shared TestModule.c -o TestModule.so +// The actual contents of the test module is not important here. I am using this because it +// produces an extremely tiny (but still perfectly valid) module. + +void +boom(void) +{ + char *BOOM; + *BOOM = 47; +} Index: lldb/trunk/unittests/Utility/ModuleCacheTest.cpp =================================================================== --- lldb/trunk/unittests/Utility/ModuleCacheTest.cpp +++ lldb/trunk/unittests/Utility/ModuleCacheTest.cpp @@ -0,0 +1,179 @@ +#include "gtest/gtest.h" + +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" + +#include "Plugins/ObjectFile/ELF/ObjectFileELF.h" +#include "Utility/ModuleCache.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Symbol/SymbolContext.h" + +extern const char *TestMainArgv0; + +using namespace lldb_private; +using namespace lldb; + +namespace +{ + +class ModuleCacheTest : public testing::Test +{ +public: + static void + SetUpTestCase(); + + static void + TearDownTestCase(); + +protected: + static FileSpec s_cache_dir; + static llvm::SmallString<128> s_test_executable; + + void + TryGetAndPut(const FileSpec &cache_dir, const char *hostname, bool expect_download); +}; +} + +FileSpec ModuleCacheTest::s_cache_dir; +llvm::SmallString<128> ModuleCacheTest::s_test_executable; + +static const char dummy_hostname[] = "dummy_hostname"; +static const char dummy_remote_dir[] = "bin"; +static const char module_name[] = "TestModule.so"; +static const char module_uuid[] = "F4E7E991-9B61-6AD4-0073-561AC3D9FA10-C043A476"; +static const uint32_t uuid_bytes = 20; +static const size_t module_size = 5602; + +static FileSpec +GetDummyRemotePath() +{ + FileSpec fs("/", false, FileSpec::ePathSyntaxPosix); + fs.AppendPathComponent(dummy_remote_dir); + fs.AppendPathComponent(module_name); + return fs; +} + +static FileSpec +GetUuidView(FileSpec spec) +{ + spec.AppendPathComponent(".cache"); + spec.AppendPathComponent(module_uuid); + spec.AppendPathComponent(module_name); + return spec; +} + +static FileSpec +GetSysrootView(FileSpec spec, const char *hostname) +{ + spec.AppendPathComponent(hostname); + spec.AppendPathComponent(dummy_remote_dir); + spec.AppendPathComponent(module_name); + return spec; +} + +void +ModuleCacheTest::SetUpTestCase() +{ + HostInfo::Initialize(); + ObjectFileELF::Initialize(); + + FileSpec tmpdir_spec; + HostInfo::GetLLDBPath(lldb::ePathTypeLLDBTempSystemDir, s_cache_dir); + + llvm::StringRef exe_folder = llvm::sys::path::parent_path(TestMainArgv0); + s_test_executable = exe_folder; + llvm::sys::path::append(s_test_executable, "Inputs", module_name); +} + +void +ModuleCacheTest::TearDownTestCase() +{ + ObjectFileELF::Terminate(); + HostInfo::Terminate(); +} + +static void +VerifyDiskState(const FileSpec &cache_dir, const char *hostname) +{ + FileSpec uuid_view = GetUuidView(cache_dir); + EXPECT_TRUE(uuid_view.Exists()) << "uuid_view is: " << uuid_view.GetCString(); + EXPECT_EQ(module_size, uuid_view.GetByteSize()); + + FileSpec sysroot_view = GetSysrootView(cache_dir, hostname); + EXPECT_TRUE(sysroot_view.Exists()) << "sysroot_view is: " << sysroot_view.GetCString(); + EXPECT_EQ(module_size, sysroot_view.GetByteSize()); +} + +void +ModuleCacheTest::TryGetAndPut(const FileSpec &cache_dir, const char *hostname, bool expect_download) +{ + ModuleCache mc; + ModuleSpec module_spec; + module_spec.GetFileSpec() = GetDummyRemotePath(); + module_spec.GetUUID().SetFromCString(module_uuid, uuid_bytes); + module_spec.SetObjectSize(module_size); + ModuleSP module_sp; + bool did_create; + bool download_called = false; + + Error error = mc.GetAndPut( + cache_dir, hostname, module_spec, + [this, &download_called](const ModuleSpec &module_spec, const FileSpec &tmp_download_file_spec) { + download_called = true; + EXPECT_STREQ(GetDummyRemotePath().GetCString(), module_spec.GetFileSpec().GetCString()); + std::error_code ec = llvm::sys::fs::copy_file(s_test_executable, tmp_download_file_spec.GetCString()); + EXPECT_FALSE(ec); + return Error(); + }, + [](const ModuleSP &module_sp, const FileSpec &tmp_download_file_spec) { return Error("Not supported."); }, + module_sp, &did_create); + EXPECT_EQ(expect_download, download_called); + + EXPECT_TRUE(error.Success()) << "Error was: " << error.AsCString(); + EXPECT_TRUE(did_create); + ASSERT_TRUE(bool(module_sp)); + + SymbolContextList sc_list; + EXPECT_EQ(1u, module_sp->FindFunctionSymbols(ConstString("boom"), eFunctionNameTypeFull, sc_list)); + EXPECT_STREQ(GetDummyRemotePath().GetCString(), module_sp->GetPlatformFileSpec().GetCString()); + EXPECT_STREQ(module_uuid, module_sp->GetUUID().GetAsString().c_str()); +} + +TEST_F(ModuleCacheTest, GetAndPut) +{ + FileSpec test_cache_dir = s_cache_dir; + test_cache_dir.AppendPathComponent("GetAndPut"); + + const bool expect_download = true; + TryGetAndPut(test_cache_dir, dummy_hostname, expect_download); + VerifyDiskState(test_cache_dir, dummy_hostname); +} + +TEST_F(ModuleCacheTest, GetAndPutUuidExists) +{ + FileSpec test_cache_dir = s_cache_dir; + test_cache_dir.AppendPathComponent("GetAndPutUuidExists"); + + FileSpec uuid_view = GetUuidView(test_cache_dir); + std::error_code ec = llvm::sys::fs::create_directories(uuid_view.GetDirectory().GetCString()); + ASSERT_FALSE(ec); + ec = llvm::sys::fs::copy_file(s_test_executable, uuid_view.GetCString()); + ASSERT_FALSE(ec); + + const bool expect_download = false; + TryGetAndPut(test_cache_dir, dummy_hostname, expect_download); + VerifyDiskState(test_cache_dir, dummy_hostname); +} + +TEST_F(ModuleCacheTest, GetAndPutStrangeHostname) +{ + FileSpec test_cache_dir = s_cache_dir; + test_cache_dir.AppendPathComponent("GetAndPutStrangeHostname"); + + const bool expect_download = true; + TryGetAndPut(test_cache_dir, "tab\tcolon:asterisk*", expect_download); + VerifyDiskState(test_cache_dir, "tab_colon_asterisk_"); +}