diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt --- a/llvm/CMakeLists.txt +++ b/llvm/CMakeLists.txt @@ -402,14 +402,6 @@ set(LLVM_ENABLE_Z3_SOLVER_DEFAULT "${Z3_FOUND}") -if (LLVM_ENABLE_DEBUGINFOD_CLIENT) - set(LLVM_WITH_CURL 1) - set(CURL_LIBRARY "-lcurl") - find_package(CURL 7.74.0 REQUIRED) - add_compile_definitions( - LLVM_ENABLE_DEBUGINFOD_CLIENT - LLVM_WITH_CURL) -endif() if( LLVM_TARGETS_TO_BUILD STREQUAL "all" ) set( LLVM_TARGETS_TO_BUILD ${LLVM_ALL_TARGETS} ) diff --git a/llvm/include/llvm/Debuginfod/Debuginfod.h b/llvm/include/llvm/Debuginfod/Debuginfod.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Debuginfod/Debuginfod.h @@ -0,0 +1,44 @@ +//===-- llvm/Support/Debuginfod.h - Debuginfod client library ---*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the declarations of the debuginfod::fetchInfo +/// function and the debuginfod::AssetType enum class +/// +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_DEBUGINFOD_H +#define LLVM_SUPPORT_DEBUGINFOD_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MemoryBuffer.h" + +namespace llvm { + +/// DebuginfodAsset - This enum class specifies the types of +/// debugging information that can be requested from a debuginfod +/// server. +enum class DebuginfodAssetType { Executable, Debuginfo, Source }; + +/// Fetch a debuginfod asset to a file in a local cache and return the cached +/// file path. First queries the local cache in the given directory path, +/// followed by the debuginfod servers at the given urls for the specified +/// type of information about the given build ID. Source files are specified +/// by their absolute path provided in the Description. A callback function +/// may optionally be provided for further processing of the fetched asset. +Expected> fetchDebuginfo( + StringRef CacheDirectoryPath, ArrayRef DebuginfodUrls, + StringRef BuildID, DebuginfodAssetType Type, StringRef Description = "", + std::function)> AddBuffer = + [](size_t Task, std::unique_ptr MB) {}); + +} // end namespace llvm + +#endif diff --git a/llvm/include/llvm/Support/HTTPClient.h b/llvm/include/llvm/Support/HTTPClient.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Support/HTTPClient.h @@ -0,0 +1,32 @@ +//===-- llvm/Support/HTTPClient.h - HTTP client library ---*- C++ -------*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the declarations of the HTTPResponse struct +/// and httpGet function. +/// +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_HTTP_CLIENT_H +#define LLVM_SUPPORT_HTTP_CLIENT_H + +#include "llvm/Support/Error.h" + +namespace llvm { + +struct HTTPResponse { + long Code = 0; + std::string Body; +}; + +Expected httpGet(const Twine &Url); + +} // end namespace llvm + +#endif // LLVM_SUPPORT_HTTP_CLIENT_H diff --git a/llvm/lib/CMakeLists.txt b/llvm/lib/CMakeLists.txt --- a/llvm/lib/CMakeLists.txt +++ b/llvm/lib/CMakeLists.txt @@ -12,6 +12,7 @@ add_subdirectory(BinaryFormat) add_subdirectory(Bitcode) add_subdirectory(Bitstream) +add_subdirectory(Debuginfod) add_subdirectory(DWARFLinker) add_subdirectory(Extensions) add_subdirectory(Frontend) diff --git a/llvm/lib/Debuginfod/CMakeLists.txt b/llvm/lib/Debuginfod/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/llvm/lib/Debuginfod/CMakeLists.txt @@ -0,0 +1,11 @@ +if(LLVM_ENABLE_CURL) + add_llvm_component_library(LLVMDebuginfod + Debuginfod.cpp + + ADDITIONAL_HEADER_DIRS + ${LLVM_MAIN_INCLUDE_DIR}/llvm/Debuginfod + + LINK_COMPONENTS + Support + ) +endif() diff --git a/llvm/lib/Debuginfod/Debuginfod.cpp b/llvm/lib/Debuginfod/Debuginfod.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Debuginfod/Debuginfod.cpp @@ -0,0 +1,105 @@ +//===-- llvm/Support/Debuginfod.cpp - Debuginfod client library -----------===// +//-*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// This file defines the fetchInfo function, which retrieves +/// any of the three supported asset types: (executable, debuginfo, source file) +/// associated with a build-id from debuginfod servers. If a source file is to +/// be fetched, its absolute path must be specified in the Description argument +/// to fetchInfo. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/Debuginfod/Debuginfod.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/CachePruning.h" +#include "llvm/Support/Caching.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/HTTPClient.h" +#include "llvm/Support/xxhash.h" + +namespace llvm { + +#define DEBUG_TYPE "DEBUGINFOD" + +Expected> fetchDebuginfo( + StringRef CacheDirectoryPath, ArrayRef DebuginfodUrls, + StringRef BuildID, DebuginfodAssetType Type, StringRef Description, + std::function)> AddBuffer) { + LLVM_DEBUG(dbgs() << "fetching info, debuginfod urls size = " + << DebuginfodUrls.size() << "\n";); + std::string Suffix; + switch (Type) { + case DebuginfodAssetType::Executable: + Suffix = "executable"; + break; + case DebuginfodAssetType::Debuginfo: + Suffix = "debuginfo"; + break; + case DebuginfodAssetType::Source: + // Description is the absolute source path + Suffix = "source" + Description.str(); + break; + } + + std::string UniqueKey = utostr(xxHash64((BuildID + Suffix).str())); + + Expected CacheOrErr = localCache( + "Debuginfod-client", ".debuginfod-client", CacheDirectoryPath, AddBuffer); + if (Error Err = CacheOrErr.takeError()) + return Err; + + NativeObjectCache &Cache = *CacheOrErr; + + // We choose an arbitrary Task parameter as we do not make use of it. + unsigned Task = 0; + AddStreamFn CacheAddStream = Cache(Task, UniqueKey); + + SmallString<64> AbsCachedAssetPath; + sys::path::append(AbsCachedAssetPath, CacheDirectoryPath, + "llvmcache-" + UniqueKey); + + if (!CacheAddStream) { + LLVM_DEBUG(dbgs() << "cache hit\n";); + return AbsCachedAssetPath; + } + + LLVM_DEBUG(dbgs() << "cache miss, UniqueKey = " << UniqueKey << "\n";); + + // The asset was not found in the local cache, so we must query + // the debuginfod servers. + for (auto &ServerUrl : DebuginfodUrls) { + SmallString<64> AssetUrl; + sys::path::append(AssetUrl, ServerUrl, "buildid", BuildID, Suffix); + + Expected ResponseOrErr = httpGet(AssetUrl); + + if (Error Err = ResponseOrErr.takeError()) + return Err; + + HTTPResponse &Resp = *ResponseOrErr; + if (Resp.Code == 200) { + // We have retrieved the asset from this server, + // so we add it to the file cache. + auto Stream = CacheAddStream(Task); + *Stream->OS << Resp.Body; + + // Return the path to the asset on disk. + return AbsCachedAssetPath; + } + } + + return createStringError(errc::argument_out_of_domain, "build id not found"); +} + +#undef DEBUG_TYPE + +} // end namespace llvm diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt --- a/llvm/lib/Support/CMakeLists.txt +++ b/llvm/lib/Support/CMakeLists.txt @@ -74,6 +74,11 @@ set(system_libs ${system_libs} ${Z3_LIBRARIES}) endif() +# Link LibCURL if the user wants it +if (LLVM_ENABLE_CURL) + set(system_libs ${system_libs} ${CURL_LIBRARIES}) +endif() + # Override the C runtime allocator on Windows and embed it into LLVM tools & libraries if(LLVM_INTEGRATED_CRT_ALLOC) if (CMAKE_BUILD_TYPE AND NOT ${LLVM_USE_CRT_${uppercase_CMAKE_BUILD_TYPE}} MATCHES "^(MT|MTd)$") @@ -155,6 +160,7 @@ GlobPattern.cpp GraphWriter.cpp Hashing.cpp + HTTPClient.cpp InitLLVM.cpp InstructionCost.cpp IntEqClasses.cpp diff --git a/llvm/lib/Support/HTTPClient.cpp b/llvm/lib/Support/HTTPClient.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Support/HTTPClient.cpp @@ -0,0 +1,72 @@ +//===-- llvm/Support/HTTPClient.cpp - HTTP client library -------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// This file defines the httpGet function, implemented using libcurl. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/HTTPClient.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" + +#include + +namespace llvm { + +#define DEBUG_TYPE "HTTPClient" + +static size_t writeMemoryCallback(char *Contents, size_t Size, size_t NMemb, + std::vector *Buffer) { + size_t ChunkSize = Size * NMemb; + size_t BufferSize = Buffer->size(); + Buffer->resize(BufferSize + ChunkSize); + memcpy(&(Buffer[BufferSize]), Contents, ChunkSize); + return ChunkSize; +} + +Expected httpGet(const Twine &Url) { + + LLVM_DEBUG(dbgs() << "getting Url " << Url << "\n";); + + CURL *Curl = curl_easy_init(); + CURLcode CurlRes; + if (!Curl) { + return createStringError(errc::io_error, "http library error"); + } + + curl_easy_setopt(Curl, CURLOPT_URL, Url.str().c_str()); + curl_easy_setopt(Curl, CURLOPT_FOLLOWLOCATION, 1); + curl_easy_setopt(Curl, CURLOPT_WRITEFUNCTION, writeMemoryCallback); + + std::vector Buffer; + curl_easy_setopt(Curl, CURLOPT_WRITEDATA, &Buffer); + + LLVM_DEBUG(dbgs() << "performing the curl\n";); + CurlRes = curl_easy_perform(Curl); + LLVM_DEBUG(dbgs() << "got the CurlRes\n";); + + curl_easy_cleanup(Curl); + + if (CurlRes != CURLE_OK) { + return createStringError(errc::io_error, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(CurlRes)); + } + + HTTPResponse Resp; + Resp.Body = Buffer.size() ? "" : std::string(Buffer.begin(), Buffer.end()); + curl_easy_getinfo(Curl, CURLINFO_RESPONSE_CODE, &Resp.Code); + return Resp; +} + +#undef DEBUG_TYPE + +} // end namespace llvm diff --git a/llvm/test/lit.cfg.py b/llvm/test/lit.cfg.py --- a/llvm/test/lit.cfg.py +++ b/llvm/test/lit.cfg.py @@ -399,3 +399,6 @@ if config.expensive_checks: config.available_features.add('expensive_checks') + +if getattr(config, 'enable_debuginfod_client', False): + config.available_features.add('debuginfod_client') diff --git a/llvm/test/lit.site.cfg.py.in b/llvm/test/lit.site.cfg.py.in --- a/llvm/test/lit.site.cfg.py.in +++ b/llvm/test/lit.site.cfg.py.in @@ -1,5 +1,12 @@ @LIT_SITE_CFG_IN_HEADER@ + +# Set attribute value if it is unset. +def set_default(attr, value): + if not getattr(config, attr, None): + setattr(config, attr, value) + +import lit.util import sys config.host_triple = "@LLVM_HOST_TRIPLE@" @@ -37,6 +44,7 @@ config.llvm_use_intel_jitevents = @LLVM_USE_INTEL_JITEVENTS@ config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@" config.have_zlib = @LLVM_ENABLE_ZLIB@ +set_default("enable_debuginfod_client", lit.util.pythonize_bool("@LLVM_ENABLE_CURL@")) config.have_libxar = @LLVM_HAVE_LIBXAR@ config.have_libxml2 = @LLVM_ENABLE_LIBXML2@ config.have_dia_sdk = @LLVM_ENABLE_DIA_SDK@ diff --git a/llvm/test/tools/llvm-debuginfod/Inputs/buildid/fake_build_id/debuginfo b/llvm/test/tools/llvm-debuginfod/Inputs/buildid/fake_build_id/debuginfo new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-debuginfod/Inputs/buildid/fake_build_id/debuginfo @@ -0,0 +1 @@ +fake_debuginfo diff --git a/llvm/test/tools/llvm-debuginfod/Inputs/buildid/fake_build_id/executable b/llvm/test/tools/llvm-debuginfod/Inputs/buildid/fake_build_id/executable new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-debuginfod/Inputs/buildid/fake_build_id/executable @@ -0,0 +1 @@ +fake_executable diff --git a/llvm/test/tools/llvm-debuginfod/Inputs/buildid/fake_build_id/source/directory/file.c b/llvm/test/tools/llvm-debuginfod/Inputs/buildid/fake_build_id/source/directory/file.c new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-debuginfod/Inputs/buildid/fake_build_id/source/directory/file.c @@ -0,0 +1 @@ +int foo = 0; diff --git a/llvm/test/tools/llvm-debuginfod/find-debuginfod-asset.py b/llvm/test/tools/llvm-debuginfod/find-debuginfod-asset.py new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-debuginfod/find-debuginfod-asset.py @@ -0,0 +1,43 @@ +from __future__ import print_function +import os +import subprocess +import sys +import threading + + +argv = sys.argv + +server_directory = argv[1] +port = argv[2] +debuginfod_find_args = argv[3:] + +# start the dummy debuginfod server +server = subprocess.Popen(['python', + '-m', 'http.server', + '--directory', + server_directory, + port], + stdout=subprocess.PIPE, + stdin=subprocess.PIPE) + +# use a watchdog to ensure the test does not run indefinitely +def kill_subprocess_and_fail_test(process): + process.kill() + os._exit(1) + +# it should not take 20 seconds or longer to test the client +watchdog = threading.Timer(20, kill_subprocess_and_fail_test, args=[server]) +watchdog.start() + +# test the client +client = subprocess.Popen(['llvm-debuginfod-find', + 'fake_build_id'] + debuginfod_find_args, + env={**os.environ, + 'DEBUGINFOD_URLS':f'http://localhost:{port}/'}) + +# client should have exit code 0 +assert(client.wait() == 0) + +# we can now safely end the test +watchdog.cancel() +server.kill() diff --git a/llvm/test/tools/llvm-debuginfod/llvm-debuginfod-find.test b/llvm/test/tools/llvm-debuginfod/llvm-debuginfod-find.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-debuginfod/llvm-debuginfod-find.test @@ -0,0 +1,4 @@ +# REQUIRES: debuginfod_client +# RUN: python %S/find-debuginfod-asset.py %S 13576 --executable +# RUN: python %S/find-debuginfod-asset.py %S 13577 --debuginfo +# RUN: python %S/find-debuginfod-asset.py %S 13578 --source=/directory/file.c diff --git a/llvm/tools/llvm-debuginfod/CMakeLists.txt b/llvm/tools/llvm-debuginfod/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-debuginfod/CMakeLists.txt @@ -0,0 +1,13 @@ +if (LLVM_ENABLE_CURL) + set(LLVM_LINK_COMPONENTS + Debuginfod + Support + ) + add_llvm_tool(llvm-debuginfod-find + llvm-debuginfod-find.cpp + ) + set_property(TARGET llvm-debuginfod-find PROPERTY LLVM_SYSTEM_LIBS ${imported_libs}) + if(LLVM_INSTALL_BINUTILS_SYMLINKS) + add_llvm_tool_symlink(debuginfod-find llvm-debuginfod-find) + endif() +endif() diff --git a/llvm/tools/llvm-debuginfod/llvm-debuginfod-find.cpp b/llvm/tools/llvm-debuginfod/llvm-debuginfod-find.cpp new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-debuginfod/llvm-debuginfod-find.cpp @@ -0,0 +1,109 @@ +//===-- llvm-debuginfod-find.cpp - Simple CLI for libdebuginfod-client ----===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the llvm-debuginfod-find tool. This tool +/// queries the debuginfod servers in the DEBUGINFOD_URLS environment +/// variable (delimited by space (" ")) for the executable, +/// debuginfo, or specified source file of the binary matching the +/// given build-id. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringRef.h" +#include "llvm/Config/config.h" +#include "llvm/Debuginfod/Debuginfod.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/COM.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/StringSaver.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include + +#define DEBUG_TYPE "llvm-debuginfod-find" + +using namespace llvm; + +cl::opt InputBuildID(cl::Positional, cl::Required, + cl::desc(""), cl::init("-")); + +static cl::opt + FetchExecutable("executable", cl::init(false), + cl::desc("fetch the associated executable")); + +static cl::opt FetchDebuginfo("debuginfo", cl::init(false), + cl::desc("fetch associated debuginfo")); + +static cl::opt FetchSource("source", cl::init(""), + cl::desc("/filename")); + +ExitOnError ExitOnErr; + +int main(int argc, char **argv) { + InitLLVM X(argc, argv); + + cl::ParseCommandLineOptions(argc, argv); + + const char *DebuginfodUrlsEnv = std::getenv("DEBUGINFOD_URLS"); + if (DebuginfodUrlsEnv == NULL) { + errs() << "DEBUGINFOD_URLS not set\n"; + return 1; + } + + SmallVector DebuginfodUrls; + StringRef(DebuginfodUrlsEnv).split(DebuginfodUrls, " "); + + const char *HomeEnv = std::getenv("HOME"); + if (HomeEnv == NULL) { + LLVM_DEBUG(dbgs() << "HOME not set\n";); + return 1; + } + LLVM_DEBUG(dbgs() << "HOME = " << HomeEnv << "\n";); + SmallString<64> CacheDirectoryPath; + sys::path::append(CacheDirectoryPath, HomeEnv, ".llvmdebuginfodcache", + "debuginfod_client"); + + DebuginfodAssetType Type; + StringRef Description; + if (FetchExecutable) { + Type = DebuginfodAssetType::Executable; + } else if (FetchDebuginfo) { + Type = DebuginfodAssetType::Debuginfo; + } else if (FetchSource != "") { + Type = DebuginfodAssetType::Source; + Description = FetchSource; + } else { + llvm_unreachable("invalid asset request"); + } + + if (Type == DebuginfodAssetType::Source) { + // Print the contents of the source file + ExitOnErr(fetchDebuginfo(CacheDirectoryPath, DebuginfodUrls, InputBuildID, + Type, Description, + [](size_t Task, std::unique_ptr MB) { + outs() << MB->getBuffer(); + })); + } else { + // Print the path to the cached binary file on disk + outs() << ExitOnErr(fetchDebuginfo(CacheDirectoryPath, DebuginfodUrls, + InputBuildID, Type, Description)) + << "\n"; + } +} + +#undef DEBUG_TYPE diff --git a/llvm/unittests/CMakeLists.txt b/llvm/unittests/CMakeLists.txt --- a/llvm/unittests/CMakeLists.txt +++ b/llvm/unittests/CMakeLists.txt @@ -22,6 +22,7 @@ add_subdirectory(Bitstream) add_subdirectory(CodeGen) add_subdirectory(DebugInfo) +add_subdirectory(Debuginfod) add_subdirectory(Demangle) add_subdirectory(ExecutionEngine) add_subdirectory(FileCheck) diff --git a/llvm/unittests/Debuginfod/CMakeLists.txt b/llvm/unittests/Debuginfod/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/llvm/unittests/Debuginfod/CMakeLists.txt @@ -0,0 +1,9 @@ +if (LLVM_ENABLE_CURL) + set(LLVM_LINK_COMPONENTS + Debuginfod + ) + + add_llvm_unittest(DebuginfodTests + DebuginfodTests.cpp + ) +endif() diff --git a/llvm/unittests/Debuginfod/DebuginfodTests.cpp b/llvm/unittests/Debuginfod/DebuginfodTests.cpp new file mode 100644 --- /dev/null +++ b/llvm/unittests/Debuginfod/DebuginfodTests.cpp @@ -0,0 +1,19 @@ +//===-- llvm/unittest/Support/DebuginfodTests.cpp - unit tests --*- C++ -*-===// +// +// 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 "llvm/Debuginfod/Debuginfod.h" + +#include "gtest/gtest.h" + +TEST(DebuginfodTests, noDebuginfodUrlsFetchInfoTest) { + auto InfoOrErr = fetchDebuginfo("./", {}, "fakeBuildId", + llvm::DebuginfodAssetType::Executable, ""); + handleAllErrors(InfoOrErr.takeError(), [](const llvm::StringError &SE) { + llvm::dbgs() << "got a StringError as expected\n"; + }); +} diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt --- a/llvm/unittests/Support/CMakeLists.txt +++ b/llvm/unittests/Support/CMakeLists.txt @@ -41,6 +41,7 @@ GlobPatternTest.cpp HashBuilderTest.cpp Host.cpp + HTTPClient.cpp IndexedAccessorTest.cpp InstructionCostTest.cpp ItaniumManglingCanonicalizerTest.cpp diff --git a/llvm/unittests/Support/HTTPClient.cpp b/llvm/unittests/Support/HTTPClient.cpp new file mode 100644 --- /dev/null +++ b/llvm/unittests/Support/HTTPClient.cpp @@ -0,0 +1,23 @@ +//===-- llvm/unittest/Support/HTTPClient.cpp - unit tests -------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifdef LLVM_WITH_CURL + +#include "llvm/Support/HTTPClient.h" + +#include "gtest/gtest.h" + +TEST(HTTPClientTests, invalidUrlTest) { + std::string invalidUrl = "llvm is fun"; + handleAllErrors(llvm::httpGet(invalidUrl).takeError(), + [](const llvm::StringError &SE) { + llvm::dbgs() << "got a StringError as expected\n"; + }); +} + +#endif