diff --git a/recipes/userver/all/conandata.yml b/recipes/userver/all/conandata.yml new file mode 100644 index 00000000000000..e09399a66831b3 --- /dev/null +++ b/recipes/userver/all/conandata.yml @@ -0,0 +1,4 @@ +sources: + "cci.20231018": + url: "https://github.com/userver-framework/userver/archive/0d1ecbb7dc664e20616c60a16bd91def20504130.tar.gz" + sha256: "8f1d0482a7fd79a46b9744a08a8b3e6088c5b43538ee15c89a5b4b3f76e70c80" diff --git a/recipes/userver/all/conanfile.py b/recipes/userver/all/conanfile.py new file mode 100644 index 00000000000000..8e26b5fb7e539e --- /dev/null +++ b/recipes/userver/all/conanfile.py @@ -0,0 +1,655 @@ +import os + +from conan import ConanFile +from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout +from conan.tools.files import get, copy, export_conandata_patches, apply_conandata_patches +from conan.errors import ConanInvalidConfiguration + +required_conan_version = ">=1.53.0" + +class UserverConan(ConanFile): + name = 'userver' + description = 'The C++ Asynchronous Framework' + topics = ('framework', 'coroutines', 'asynchronous') + url = 'https://github.com/userver-framework/userver' + homepage = 'https://userver.tech/' + license = 'Apache-2.0' + package_type = "library" + + settings = 'os', 'arch', 'compiler', 'build_type' + options = { + 'shared': [True, False], + 'fPIC': [True, False], + 'lto': [True, False], + 'with_jemalloc': [True, False], + 'with_mongodb': [True, False], + 'with_postgresql': [True, False], + 'with_postgresql_extra': [True, False], + 'with_redis': [True, False], + 'with_grpc': [True, False], + 'with_clickhouse': [True, False], + 'with_rabbitmq': [True, False], + 'with_utest': [True, False], + 'namespace': ['ANY'], + 'namespace_begin': ['ANY'], + 'namespace_end': ['ANY'], + } + + default_options = { + 'shared': False, + 'fPIC': True, + 'lto': True, + 'with_jemalloc': False, + 'with_mongodb': True, + 'with_postgresql': True, + 'with_postgresql_extra': False, + 'with_redis': True, + 'with_grpc': True, + 'with_clickhouse': True, + 'with_rabbitmq': True, + 'with_utest': True, + 'namespace': 'userver', + 'namespace_begin': 'namespace userver {', + 'namespace_end': '}', + 'mongo-c-driver/*:with_sasl': 'cyrus', + } + + @property + def _source_subfolder(self): + return 'source' + + @property + def _build_subfolder(self): + return os.path.join(self.build_folder, 'userver') + + def configure(self): + if self.options.shared: + del self.options.fPIC + + def layout(self): + cmake_layout(self, src_folder="src") + + def requirements(self): + self.requires('boost/1.79.0', transitive_headers=True) + self.requires('c-ares/1.19.1') + self.requires('cctz/2.3', transitive_headers=True) + self.requires('concurrentqueue/1.0.3', transitive_headers=True) + self.requires('cryptopp/8.7.0') + self.requires('fmt/8.1.1', transitive_headers=True) + self.requires('libnghttp2/1.51.0') + self.requires('libcurl/7.86.0') + self.requires('libev/4.33') + self.requires('http_parser/2.9.4') + self.requires('openssl/1.1.1s') + self.requires('rapidjson/cci.20220822', transitive_headers=True) + self.requires('yaml-cpp/0.7.0') + self.requires('zlib/1.2.13') + + if self.options.with_jemalloc: + self.requires('jemalloc/5.3.0') + if self.options.with_grpc: + self.requires( + 'grpc/1.48.4', transitive_headers=True, transitive_libs=True, + ) + self.requires( + 'googleapis/cci.20230501', + transitive_headers=True, + transitive_libs=True, + ) + self.requires( + 'grpc-proto/cci.20220627', + transitive_headers=True, + transitive_libs=True, + ) + self.requires('protobuf/3.21.12', override=True) + if self.options.with_postgresql: + self.requires('libpq/14.5') + if self.options.with_mongodb: + self.requires('cyrus-sasl/2.1.27') + self.requires( + 'mongo-c-driver/1.22.0', + transitive_headers=True, + transitive_libs=True, + ) + if self.options.with_redis: + self.requires('hiredis/1.0.2') + if self.options.with_rabbitmq: + self.requires('amqp-cpp/4.3.16') + if self.options.with_clickhouse: + self.requires('clickhouse-cpp/2.4.0') + self.requires( + 'abseil/20230125.3', + transitive_headers=True, + transitive_libs=True, + ) + if self.options.with_utest: + self.requires( + 'gtest/1.12.1', transitive_headers=True, transitive_libs=True, + ) + self.requires( + 'benchmark/1.6.2', + transitive_headers=True, + transitive_libs=True, + ) + + def export_sources(self): + export_conandata_patches(self) + + def source(self): + get(self, **self.conan_data["sources"][self.version], strip_root=True, + destination=self.source_folder) + + def validate(self): + if self.settings.os == "Windows": + raise ConanInvalidConfiguration("userver can't be built on Windows") + if self.options.shared: + raise ConanInvalidConfiguration("userver can't be built as shared") + if self.dependencies['mongo-c-driver'].options.with_sasl != 'cyrus': + raise ConanInvalidConfiguration( + f'{self.ref} requires mongo-c-driver with_sasl cyrus', + ) + + def generate(self): + apply_conandata_patches(self) + tool_ch = CMakeToolchain(self) + tool_ch.variables['CMAKE_FIND_DEBUG_MODE'] = False + + tool_ch.variables['USERVER_OPEN_SOURCE_BUILD'] = True + tool_ch.variables['USERVER_CONAN'] = True + tool_ch.variables['USERVER_IS_THE_ROOT_PROJECT'] = False + tool_ch.variables['USERVER_DOWNLOAD_PACKAGES'] = True + tool_ch.variables['USERVER_FEATURE_DWCAS'] = True + tool_ch.variables['USERVER_NAMESPACE'] = self.options.namespace + tool_ch.variables[ + 'USERVER_NAMESPACE_BEGIN' + ] = self.options.namespace_begin + tool_ch.variables['USERVER_NAMESPACE_END'] = self.options.namespace_end + + tool_ch.variables['USERVER_LTO'] = self.options.lto + tool_ch.variables[ + 'USERVER_FEATURE_JEMALLOC' + ] = self.options.with_jemalloc + tool_ch.variables[ + 'USERVER_FEATURE_MONGODB' + ] = self.options.with_mongodb + tool_ch.variables[ + 'USERVER_FEATURE_POSTGRESQL' + ] = self.options.with_postgresql + tool_ch.variables[ + 'USERVER_FEATURE_PATCH_LIBPQ' + ] = self.options.with_postgresql_extra + tool_ch.variables['USERVER_FEATURE_REDIS'] = self.options.with_redis + tool_ch.variables['USERVER_FEATURE_GRPC'] = self.options.with_grpc + tool_ch.variables[ + 'USERVER_FEATURE_CLICKHOUSE' + ] = self.options.with_clickhouse + tool_ch.variables[ + 'USERVER_FEATURE_RABBITMQ' + ] = self.options.with_rabbitmq + tool_ch.variables['USERVER_FEATURE_UTEST'] = self.options.with_utest + tool_ch.variables[ + 'USERVER_FEATURE_TESTSUITE' + ] = self.options.with_utest + + tool_ch.generate() + + CMakeDeps(self).generate() + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + @property + def _cmake_subfolder(self): + return os.path.join(self.package_folder, 'cmake') + + def package(self): + copy(self, pattern='LICENSE', src=self.source_folder, dst='licenses') + + copy( + self, + pattern='*', + dst=os.path.join(self.package_folder, 'scripts'), + src=os.path.join(self.source_folder, 'scripts'), + keep_path=True, + ) + + copy( + self, + pattern='*', + dst=os.path.join( + self.package_folder, 'include', 'function_backports', + ), + src=os.path.join( + self.source_folder, + 'third_party', + 'function_backports', + 'include', + ), + keep_path=True, + ) + + def copy_component(component): + copy( + self, + pattern='*', + dst=os.path.join(self.package_folder, 'include', component), + src=os.path.join(self.source_folder, component, 'include'), + keep_path=True, + ) + copy( + self, + pattern='*.a', + dst=os.path.join(self.package_folder, 'lib'), + src=os.path.join(self._build_subfolder, component), + keep_path=False, + ) + copy( + self, + pattern='*.so', + dst=os.path.join(self.package_folder, 'lib'), + src=os.path.join(self._build_subfolder, component), + keep_path=False, + ) + + copy_component('core') + copy_component('universal') + + if self.options.with_grpc: + copy_component('grpc') + copy( + self, + pattern='*', + dst=os.path.join(self.package_folder, 'include', 'grpc'), + src=os.path.join( + self.source_folder, 'grpc', 'handlers', 'include', + ), + keep_path=True, + ) + copy( + self, + pattern='GrpcTargets.cmake', + dst=os.path.join(self.package_folder, 'cmake'), + src=os.path.join(self.source_folder, 'cmake'), + keep_path=True, + ) + + with open( + os.path.join( + self.package_folder, 'cmake', 'GrpcConan.cmake', + ), + 'a+', + ) as grpc_file: + grpc_file.write('\nset(USERVER_CONAN TRUE)') + grpc_file.write('\nset(PYTHON "python3")') + if self.options.with_utest: + copy( + self, + pattern='*', + dst=os.path.join(self.package_folder, 'include', 'utest'), + src=os.path.join( + self.source_folder, 'core', 'testing', 'include', + ), + keep_path=True, + ) + copy( + self, + pattern='*', + dst=os.path.join(self.package_folder, 'testsuite'), + src=os.path.join(self.source_folder, 'testsuite'), + keep_path=True, + ) + copy( + self, + pattern='AddGoogleTests.cmake', + dst=os.path.join(self.package_folder, 'cmake'), + src=os.path.join(self.source_folder, 'cmake'), + keep_path=True, + ) + if self.options.with_grpc or self.options.with_utest: + copy( + self, + pattern='UserverTestsuite.cmake', + dst=os.path.join(self.package_folder, 'cmake'), + src=os.path.join(self.source_folder, 'cmake'), + keep_path=True, + ) + if self.options.with_postgresql: + copy_component('postgresql') + + if self.options.with_mongodb: + copy_component('mongo') + + if self.options.with_redis: + copy_component('redis') + + if self.options.with_rabbitmq: + copy_component('rabbitmq') + + if self.options.with_clickhouse: + copy_component('clickhouse') + + @property + def _userver_components(self): + def abseil(): + return ['abseil::abseil'] + + def ares(): + return ['c-ares::c-ares'] + + def fmt(): + return ['fmt::fmt'] + + def curl(): + return ['libcurl::libcurl'] + + def cryptopp(): + return ['cryptopp::cryptopp'] + + def cctz(): + return ['cctz::cctz'] + + def boost(): + return ['boost::boost'] + + def concurrentqueue(): + return ['concurrentqueue::concurrentqueue'] + + def yaml(): + return ['yaml-cpp::yaml-cpp'] + + def libev(): + return ['libev::libev'] + + def http_parser(): + return ['http_parser::http_parser'] + + def libnghttp2(): + return ['libnghttp2::libnghttp2'] + + def openssl(): + return ['openssl::openssl'] + + def rapidjson(): + return ['rapidjson::rapidjson'] + + def zlib(): + return ['zlib::zlib'] + + def jemalloc(): + return ['jemalloc::jemalloc'] if self.options.with_jemalloc else [] + + def grpc(): + return ['grpc::grpc'] if self.options.with_grpc else [] + + def googleapis(): + return ['googleapis::googleapis'] if self.options.with_grpc else [] + + def grpcproto(): + return ['grpc-proto::grpc-proto'] if self.options.with_grpc else [] + + def postgresql(): + return ['libpq::pq'] if self.options.with_postgresql else [] + + def gtest(): + return ['gtest::gtest'] if self.options.with_utest else [] + + def benchmark(): + return ['benchmark::benchmark'] if self.options.with_utest else [] + + def mongo(): + return ( + ['mongo-c-driver::mongo-c-driver'] + if self.options.with_mongodb + else [] + ) + + def cyrussasl(): + return ( + ['cyrus-sasl::cyrus-sasl'] if self.options.with_mongodb else [] + ) + + def hiredis(): + return ['hiredis::hiredis'] if self.options.with_redis else [] + + def amqpcpp(): + return ['amqp-cpp::amqp-cpp'] if self.options.with_rabbitmq else [] + + def clickhouse(): + return ( + ['clickhouse-cpp::clickhouse-cpp'] + if self.options.with_clickhouse + else [] + ) + + userver_components = [ + { + 'target': 'core', + 'lib': 'core', + 'requires': ( + ['core-internal', 'universal'] + + abseil() + + fmt() + + cctz() + + boost() + + concurrentqueue() + + yaml() + + libev() + + http_parser() + + libnghttp2() + + curl() + + cryptopp() + + jemalloc() + + ares() + + rapidjson() + + zlib() + ), + }, + ] + userver_components.extend( + [ + { + 'target': 'universal', + 'lib': 'universal', + 'requires': ( + fmt() + + cctz() + + boost() + + concurrentqueue() + + yaml() + + cryptopp() + + jemalloc() + + openssl() + ), + }, + ], + ) + + if self.options.with_grpc: + userver_components.extend( + [ + { + 'target': 'grpc', + 'lib': 'grpc', + 'requires': ( + ['core'] + + grpc() + + googleapis() + + grpcproto() + ), + }, + { + 'target': 'grpc-handlers', + 'lib': 'grpc-handlers', + 'requires': ['core'] + grpc(), + }, + { + 'target': 'grpc-handlers-proto', + 'lib': 'grpc-handlers-proto', + 'requires': ['core'] + grpc(), + }, + { + 'target': 'api-common-protos', + 'lib': 'api-common-protos', + 'requires': ['grpc'], + }, + ], + ) + if self.options.with_utest: + userver_components.extend( + [ + { + 'target': 'utest', + 'lib': 'utest', + 'requires': ['core'] + gtest(), + }, + { + 'target': 'ubench', + 'lib': 'ubench', + 'requires': ['core'] + benchmark(), + }, + ], + ) + if self.options.with_postgresql: + userver_components.extend( + [ + { + 'target': 'postgresql', + 'lib': 'postgresql', + 'requires': ['core'] + postgresql(), + }, + ], + ) + if self.options.with_mongodb: + userver_components.extend( + [ + { + 'target': 'mongo', + 'lib': 'mongo', + 'requires': ['core'] + mongo() + cyrussasl(), + }, + ], + ) + if self.options.with_redis: + userver_components.extend( + [ + { + 'target': 'redis', + 'lib': 'redis', + 'requires': ['core'] + hiredis(), + }, + ], + ) + if self.options.with_rabbitmq: + userver_components.extend( + [ + { + 'target': 'rabbitmq', + 'lib': 'rabbitmq', + 'requires': ['core'] + amqpcpp(), + }, + ], + ) + if self.options.with_clickhouse: + userver_components.extend( + [ + { + 'target': 'clickhouse', + 'lib': 'clickhouse', + 'requires': ['core'] + clickhouse(), + }, + ], + ) + return userver_components + + def package_info(self): + + debug = ( + 'd' + if self.settings.build_type == 'Debug' + and self.settings.os == 'Windows' + else '' + ) + + def get_lib_name(module): + return f'userver-{module}{debug}' + + def add_components(components): + for component in components: + conan_component = component['target'] + cmake_target = component['target'] + cmake_component = component['lib'] + lib_name = get_lib_name(component['lib']) + requires = component['requires'] + # TODO: we should also define COMPONENTS names of each target + # for find_package() but not possible yet in CMakeDeps + # see https://github.com/conan-io/conan/issues/10258 + self.cpp_info.components[conan_component].set_property( + 'cmake_target_name', 'userver::' + cmake_target, + ) + if cmake_component == 'grpc': + self.cpp_info.components[conan_component].libs.append( + get_lib_name('grpc-internal'), + ) + else: + self.cpp_info.components[conan_component].libs = [lib_name] + if cmake_component == 'universal': + self.cpp_info.components[ + cmake_component + ].includedirs.append( + os.path.join('include', 'function_backports'), + ) + if cmake_component == 'core': + self.cpp_info.components[conan_component].libs.append( + get_lib_name('core-internal'), + ) + if cmake_component != 'ubench': + self.cpp_info.components[ + conan_component + ].includedirs.append( + os.path.join('include', cmake_component), + ) + + self.cpp_info.components[conan_component].requires = requires + + self.cpp_info.components['core-internal'].defines.append( + f'USERVER_NAMESPACE={self.options.namespace}', + ) + self.cpp_info.components['core-internal'].defines.append( + f'USERVER_NAMESPACE_BEGIN={self.options.namespace_begin}', + ) + self.cpp_info.components['core-internal'].defines.append( + f'USERVER_NAMESPACE_END={self.options.namespace_end}', + ) + + self.cpp_info.components['universal'].defines.append( + f'USERVER_NAMESPACE={self.options.namespace}', + ) + self.cpp_info.components['universal'].defines.append( + f'USERVER_NAMESPACE_BEGIN={self.options.namespace_begin}', + ) + self.cpp_info.components['universal'].defines.append( + f'USERVER_NAMESPACE_END={self.options.namespace_end}', + ) + + self.cpp_info.set_property('cmake_file_name', 'userver') + + add_components(self._userver_components) + + build_modules = [ + os.path.join(self._cmake_subfolder, 'UserverTestsuite.cmake'), + ] + if self.options.with_utest: + build_modules.append( + os.path.join(self._cmake_subfolder, 'AddGoogleTests.cmake'), + ) + if self.options.with_grpc: + build_modules.append( + os.path.join(self._cmake_subfolder, 'GrpcConan.cmake'), + ) + build_modules.append( + os.path.join(self._cmake_subfolder, 'GrpcTargets.cmake'), + ) + + self.cpp_info.set_property('cmake_build_modules', build_modules) \ No newline at end of file diff --git a/recipes/userver/all/test_package/CMakeLists.txt b/recipes/userver/all/test_package/CMakeLists.txt new file mode 100644 index 00000000000000..f2387fd3e80ca4 --- /dev/null +++ b/recipes/userver/all/test_package/CMakeLists.txt @@ -0,0 +1,63 @@ +cmake_minimum_required(VERSION 3.1) +project(PackageTest CXX) + +find_package(userver REQUIRED) +find_package (Python COMPONENTS Interpreter Development) + +add_library(${PROJECT_NAME}_objs OBJECT + hello.hpp + hello.cpp +) +target_link_libraries(${PROJECT_NAME}_objs PUBLIC userver::core) + +add_executable(${PROJECT_NAME}_core test_core.cpp) +target_link_libraries(${PROJECT_NAME}_core ${PROJECT_NAME}_objs userver::core) + + +if (TARGET userver::utest) + add_executable(${PROJECT_NAME}_utest test_utest.cpp) + target_link_libraries(${PROJECT_NAME}_utest ${PROJECT_NAME}_objs userver::utest) + add_google_tests(${PROJECT_NAME}_utest) +endif() + +if (TARGET userver::ubench) + add_executable(${PROJECT_NAME}_ubench test_ubench.cpp) + target_link_libraries(${PROJECT_NAME}_ubench ${PROJECT_NAME}_objs userver::ubench) + add_google_benchmark_tests(${PROJECT_NAME}_ubench) +endif() + +if (TARGET userver::postgresql) + add_executable(${PROJECT_NAME}_postgresql test_postgresql.cpp) + target_link_libraries(${PROJECT_NAME}_postgresql ${PROJECT_NAME}_objs userver::postgresql) +endif() + +if (TARGET userver::redis) + add_executable(${PROJECT_NAME}_redis test_redis.cpp) + target_link_libraries(${PROJECT_NAME}_redis ${PROJECT_NAME}_objs userver::redis) +endif() + +if (TARGET userver::rabbitmq) + add_executable(${PROJECT_NAME}_rabbitmq test_rabbitmq.cpp) + target_link_libraries(${PROJECT_NAME}_rabbitmq ${PROJECT_NAME}_objs userver::rabbitmq) +endif() + +if (TARGET userver::grpc) + add_executable(${PROJECT_NAME}_grpc test_grpc.cpp) + add_grpc_library(${PROJECT_NAME}_proto PROTOS greeter.proto) + target_link_libraries(${PROJECT_NAME}_grpc ${PROJECT_NAME}_objs userver::grpc ${PROJECT_NAME}_proto) +endif() + +if (TARGET userver::mongo) + add_executable(${PROJECT_NAME}_mongo test_mongo.cpp) + target_link_libraries(${PROJECT_NAME}_mongo ${PROJECT_NAME}_objs userver::mongo) +endif() + +if (TARGET userver::clickhouse) + add_executable(${PROJECT_NAME}_clickhouse test_clickhouse.cpp) + target_link_libraries(${PROJECT_NAME}_clickhouse ${PROJECT_NAME}_objs userver::clickhouse) +endif() + +add_executable(${PROJECT_NAME}_universal test_universal.cpp) +target_link_libraries(${PROJECT_NAME}_universal ${PROJECT_NAME}_objs userver::universal) + +add_subdirectory(hello_service) diff --git a/recipes/userver/all/test_package/conanfile.py b/recipes/userver/all/test_package/conanfile.py new file mode 100644 index 00000000000000..e0432ba94898ec --- /dev/null +++ b/recipes/userver/all/test_package/conanfile.py @@ -0,0 +1,75 @@ +import os + +from conan import ConanFile +from conan.tools.build import can_run +from conan.tools.cmake import CMake +from conan.tools.cmake import cmake_layout + + +class TestPackageConan(ConanFile): + settings = 'os', 'arch', 'compiler', 'build_type' + generators = 'CMakeToolchain', 'CMakeDeps', 'VirtualRunEnv' + test_type = 'explicit' + + def layout(self): + cmake_layout(self) + + def requirements(self): + self.requires(self.tested_reference_str) + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def test(self): + if can_run(self): + bin_path = os.path.join( + self.cpp.build.bindirs[0], 'PackageTest_core', + ) + self.run(bin_path, env='conanrun') + bin_path = os.path.join( + self.cpp.build.bindirs[0], 'PackageTest_utest', + ) + self.run(bin_path, env='conanrun') + bin_path = os.path.join( + self.cpp.build.bindirs[0], 'PackageTest_grpc', + ) + self.run(bin_path, env='conanrun') + bin_path = os.path.join( + self.cpp.build.bindirs[0], 'PackageTest_mongo', + ) + self.run(bin_path, env='conanrun') + bin_path = os.path.join( + self.cpp.build.bindirs[0], 'PackageTest_postgresql', + ) + self.run(bin_path, env='conanrun') + bin_path = os.path.join( + self.cpp.build.bindirs[0], 'PackageTest_rabbitmq', + ) + self.run(bin_path, env='conanrun') + bin_path = os.path.join( + self.cpp.build.bindirs[0], 'PackageTest_redis', + ) + self.run(bin_path, env='conanrun') + bin_path = os.path.join( + self.cpp.build.bindirs[0], 'PackageTest_clickhouse', + ) + self.run(bin_path, env='conanrun') + bin_path = os.path.join( + self.cpp.build.bindirs[0], 'PackageTest_universal', + ) + self.run(bin_path, env='conanrun') + + bin_path = os.path.join( + self.cpp.build.bindirs[0], + 'hello_service', + 'runtests-testsuite-conan-samples-hello_service', + ) + command = ' ' + folder = os.path.join( + self.source_folder, + 'hello_service', + ) + args = [bin_path, '--service-logs-pretty', '-vv', folder] + self.run(command.join(args), env='conanrun') diff --git a/recipes/userver/all/test_package/hello.cpp b/recipes/userver/all/test_package/hello.cpp new file mode 100644 index 00000000000000..d80f2ad523d842 --- /dev/null +++ b/recipes/userver/all/test_package/hello.cpp @@ -0,0 +1,38 @@ +#include "hello.hpp" + +#include + +#include + +namespace service_template { + +namespace { + +class Hello final : public userver::server::handlers::HttpHandlerBase { + public: + static constexpr std::string_view kName = "handler-hello"; + + using HttpHandlerBase::HttpHandlerBase; + + std::string HandleRequestThrow( + const userver::server::http::HttpRequest& request, + userver::server::request::RequestContext&) const override { + return service_template::SayHelloTo(request.GetArg("name")); + } +}; + +} // namespace + +std::string SayHelloTo(std::string_view name) { + if (name.empty()) { + name = "unknown user"; + } + + return fmt::format("Hello, {}!\n", name); +} + +void AppendHello(userver::components::ComponentList& component_list) { + component_list.Append(); +} + +} // namespace service_template diff --git a/recipes/userver/all/test_package/hello.hpp b/recipes/userver/all/test_package/hello.hpp new file mode 100644 index 00000000000000..d2ec2ebd248a78 --- /dev/null +++ b/recipes/userver/all/test_package/hello.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +#include + +namespace service_template { + +std::string SayHelloTo(std::string_view name); + +void AppendHello(userver::components::ComponentList& component_list); + +} // namespace service_template diff --git a/recipes/userver/all/test_package/hello_service.cpp b/recipes/userver/all/test_package/hello_service.cpp new file mode 100644 index 00000000000000..9feed3c4248e3e --- /dev/null +++ b/recipes/userver/all/test_package/hello_service.cpp @@ -0,0 +1,22 @@ +#include +#include +#include + +class Hello final : public userver::server::handlers::HttpHandlerBase { + public: + static constexpr std::string_view kName = "handler-hello-sample"; + + using HttpHandlerBase::HttpHandlerBase; + + std::string HandleRequestThrow( + const userver::server::http::HttpRequest&, + userver::server::request::RequestContext&) const override { + return "Hello world!\n"; + } +}; + +int main(int argc, char* argv[]) { + const auto component_list = + userver::components::MinimalServerComponentList().Append(); + return 0; +} diff --git a/recipes/userver/all/test_package/hello_service/CMakeLists.txt b/recipes/userver/all/test_package/hello_service/CMakeLists.txt new file mode 100644 index 00000000000000..fb9af6b989ced5 --- /dev/null +++ b/recipes/userver/all/test_package/hello_service/CMakeLists.txt @@ -0,0 +1,16 @@ +project(conan-samples-hello_service CXX) + +add_executable(${PROJECT_NAME} "hello_service.cpp") +target_link_libraries(${PROJECT_NAME} userver::core) + +userver_testsuite_add( + SERVICE_TARGET ${PROJECT_NAME} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + REQUIREMENTS ${CMAKE_CURRENT_SOURCE_DIR}/requirements.txt + PYTEST_ARGS + --service-config=${CMAKE_CURRENT_SOURCE_DIR}/static_config.yaml + --service-source-dir=${CMAKE_CURRENT_SOURCE_DIR} + --service-binary=${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME} + --config-fallback=${CMAKE_CURRENT_SOURCE_DIR}/dynamic_config_fallback.json +) + diff --git a/recipes/userver/all/test_package/hello_service/conftest.py b/recipes/userver/all/test_package/hello_service/conftest.py new file mode 100644 index 00000000000000..f22f982eed1937 --- /dev/null +++ b/recipes/userver/all/test_package/hello_service/conftest.py @@ -0,0 +1,3 @@ +# /// [registration] +pytest_plugins = ['pytest_userver.plugins.core'] +# /// [registration] diff --git a/recipes/userver/all/test_package/hello_service/dynamic_config_fallback.json b/recipes/userver/all/test_package/hello_service/dynamic_config_fallback.json new file mode 100644 index 00000000000000..f14f60bb851eb9 --- /dev/null +++ b/recipes/userver/all/test_package/hello_service/dynamic_config_fallback.json @@ -0,0 +1,76 @@ +{ + "BAGGAGE_SETTINGS": { + "allowed_keys": [] + }, + "HTTP_CLIENT_CONNECTION_POOL_SIZE": 1000, + "HTTP_CLIENT_CONNECT_THROTTLE": { + "max-size": 100, + "token-update-interval-ms": 0 + }, + "USERVER_BAGGAGE_ENABLED": false, + "USERVER_CACHES": {}, + "USERVER_CANCEL_HANDLE_REQUEST_BY_DEADLINE": false, + "USERVER_CHECK_AUTH_IN_HANDLERS": true, + "USERVER_DEADLINE_PROPAGATION_ENABLED": true, + "USERVER_DUMPS": {}, + "USERVER_FILES_CONTENT_TYPE_MAP": { + ".css": "text/css", + ".gif": "image/gif", + ".htm": "text/html", + ".html": "text/html", + ".jpeg": "image/jpeg", + ".js": "application/javascript", + ".json": "application/json", + ".md": "text/markdown", + ".png": "image/png", + ".svg": "image/svg+xml", + "__default__": "text/plain" + }, + "USERVER_HANDLER_STREAM_API_ENABLED": false, + "USERVER_HTTP_PROXY": "", + "USERVER_LOG_DYNAMIC_DEBUG": { + "force-disabled": [], + "force-enabled": [] + }, + "USERVER_LOG_REQUEST": true, + "USERVER_LOG_REQUEST_HEADERS": false, + "USERVER_LRU_CACHES": {}, + "USERVER_NO_LOG_SPANS": { + "names": [], + "prefixes": [] + }, + "USERVER_RPS_CCONTROL": { + "down-level": 1, + "down-rate-percent": 2, + "min-limit": 10, + "no-limit-seconds": 1000, + "overload-off-seconds": 3, + "overload-on-seconds": 3, + "up-level": 2, + "up-rate-percent": 2 + }, + "USERVER_RPS_CCONTROL_ACTIVATED_FACTOR_METRIC": 5, + "USERVER_RPS_CCONTROL_CUSTOM_STATUS": {}, + "USERVER_RPS_CCONTROL_ENABLED": false, + "USERVER_TASK_PROCESSOR_PROFILER_DEBUG": { + "fs-task-processor": { + "enabled": false, + "execution-slice-threshold-us": 1000000 + }, + "main-task-processor": { + "enabled": false, + "execution-slice-threshold-us": 2000 + } + }, + "USERVER_TASK_PROCESSOR_QOS": { + "default-service": { + "default-task-processor": { + "wait_queue_overload": { + "action": "ignore", + "length_limit": 5000, + "time_limit_us": 3000 + } + } + } + } +} diff --git a/recipes/userver/all/test_package/hello_service/hello_service.cpp b/recipes/userver/all/test_package/hello_service/hello_service.cpp new file mode 100644 index 00000000000000..e6abc97882ca6d --- /dev/null +++ b/recipes/userver/all/test_package/hello_service/hello_service.cpp @@ -0,0 +1,28 @@ +#include + +#include +#include +#include + +namespace samples::hello { + +class Hello final : public server::handlers::HttpHandlerBase { + public: + static constexpr std::string_view kName = "handler-hello-sample"; + + using HttpHandlerBase::HttpHandlerBase; + + std::string HandleRequestThrow( + const server::http::HttpRequest&, + server::request::RequestContext&) const override { + return "Hello world!\n"; + } +}; + +} // namespace samples::hello + +int main(int argc, char* argv[]) { + const auto component_list = + components::MinimalServerComponentList().Append(); + return utils::DaemonMain(argc, argv, component_list); +} diff --git a/recipes/userver/all/test_package/hello_service/requirements.txt b/recipes/userver/all/test_package/hello_service/requirements.txt new file mode 100644 index 00000000000000..05a6e72cc537f9 --- /dev/null +++ b/recipes/userver/all/test_package/hello_service/requirements.txt @@ -0,0 +1,4 @@ +yandex-taxi-testsuite >= 0.1.7.2 +pytest >= 7.3.0 +py >= 1.10 +websockets >= 11.0.3 diff --git a/recipes/userver/all/test_package/hello_service/static_config.yaml b/recipes/userver/all/test_package/hello_service/static_config.yaml new file mode 100644 index 00000000000000..59efb35974941a --- /dev/null +++ b/recipes/userver/all/test_package/hello_service/static_config.yaml @@ -0,0 +1,43 @@ +# yaml +components_manager: + coro_pool: + initial_size: 500 # Preallocate 500 coroutines at startup. + max_size: 1000 # Do not keep more than 1000 preallocated coroutines. + + task_processors: # Task processor is an executor for coroutine tasks + + main-task-processor: # Make a task processor for CPU-bound couroutine tasks. + worker_threads: 4 # Process tasks in 4 threads. + thread_name: main-worker # OS will show the threads of this task processor with 'main-worker' prefix. + + fs-task-processor: # Make a separate task processor for filesystem bound tasks. + thread_name: fs-worker + worker_threads: 4 + + default_task_processor: main-task-processor + + components: # Configuring components that were registered via component_list + server: + listener: # configuring the main listening socket... + port: 8080 # ...to listen on this port and... + task_processor: main-task-processor # ...process incoming requests on this task processor. + logging: + fs-task-processor: fs-task-processor + loggers: + default: + file_path: '@stderr' + level: debug + overflow_behavior: discard # Drop logs if the system is too busy to write them down. + + tracer: # Component that helps to trace execution times and requests in logs. + service-name: hello-service # "You know. You all know exactly who I am. Say my name. " (c) + + dynamic-config: # Dynamic config storage options, do nothing + fs-cache-path: '' + dynamic-config-fallbacks: # Load options from file and push them into the dynamic config storage. + fallback-path: /etc/hello_service/dynamic_config_fallback.json + + handler-hello-sample: # Finally! Our handler. + path: /hello # Registering handler by URL '/hello'. + method: GET,POST # It will only reply to GET (HEAD) and POST requests. + task_processor: main-task-processor # Run it on CPU bound task processor diff --git a/recipes/userver/all/test_package/hello_service/test_hello.py b/recipes/userver/all/test_package/hello_service/test_hello.py new file mode 100644 index 00000000000000..03f733a6d3fe8b --- /dev/null +++ b/recipes/userver/all/test_package/hello_service/test_hello.py @@ -0,0 +1,4 @@ +async def test_ping(service_client): + response = await service_client.get('/hello') + assert response.status == 200 + assert response.content == b'Hello world!\n' diff --git a/recipes/userver/all/test_package/proto/greeter.proto b/recipes/userver/all/test_package/proto/greeter.proto new file mode 100644 index 00000000000000..b239fa823b8510 --- /dev/null +++ b/recipes/userver/all/test_package/proto/greeter.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +package samples.api; + +service GreeterService { + rpc SayHello(GreetingRequest) returns(GreetingResponse) {} +} + +message GreetingRequest { + string name = 1; +} + +message GreetingResponse { + string greeting = 1; +} diff --git a/recipes/userver/all/test_package/test_clickhouse.cpp b/recipes/userver/all/test_package/test_clickhouse.cpp new file mode 100644 index 00000000000000..7c64571cc975ca --- /dev/null +++ b/recipes/userver/all/test_package/test_clickhouse.cpp @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hello.hpp" + +int main(int argc, char* argv[]) { + auto component_list = userver::components::MinimalServerComponentList() + .Append() + .Append() + .Append() + .Append() + .Append(""); + + service_template::AppendHello(component_list); + + auto size = std::distance(component_list.begin(), component_list.end()); + std::cout << size << std::endl; + + return 0; +} diff --git a/recipes/userver/all/test_package/test_core.cpp b/recipes/userver/all/test_package/test_core.cpp new file mode 100644 index 00000000000000..837631c763f0b1 --- /dev/null +++ b/recipes/userver/all/test_package/test_core.cpp @@ -0,0 +1,24 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "hello.hpp" + +int main(int argc, char* argv[]) { + auto component_list = userver::components::MinimalServerComponentList() + .Append() + .Append() + .Append() + .Append(); + + service_template::AppendHello(component_list); + + auto size = std::distance(component_list.begin(), component_list.end()); + std::cout << size << std::endl; + + return 0; +} diff --git a/recipes/userver/all/test_package/test_grpc.cpp b/recipes/userver/all/test_package/test_grpc.cpp new file mode 100644 index 00000000000000..cb413821fb0c40 --- /dev/null +++ b/recipes/userver/all/test_package/test_grpc.cpp @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "hello.hpp" + +namespace samples { + +class GreeterServiceComponent final + : public api::GreeterServiceBase::Component { + public: + static constexpr std::string_view kName = "greeter-service"; + + GreeterServiceComponent(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context) + : api::GreeterServiceBase::Component(config, context), + prefix_(config["greeting-prefix"].As()) {} + + void SayHello(SayHelloCall& call, api::GreetingRequest&& request) override; + + private: + const std::string prefix_; +}; + +void GreeterServiceComponent::SayHello( + api::GreeterServiceBase::SayHelloCall& call, + api::GreetingRequest&& request) { + api::GreetingResponse response; + response.set_greeting(fmt::format("{}, {}!", prefix_, request.name())); + + call.Finish(response); +} + +} // namespace samples + +int main(int argc, char* argv[]) { + auto component_list = userver::components::MinimalServerComponentList() + .Append() + .Append() + .Append() + .Append() + .Append("") + .Append(); + + service_template::AppendHello(component_list); + + auto size = std::distance(component_list.begin(), component_list.end()); + std::cout << size << std::endl; + + return 0; +} diff --git a/recipes/userver/all/test_package/test_mongo.cpp b/recipes/userver/all/test_package/test_mongo.cpp new file mode 100644 index 00000000000000..e2fad77137807f --- /dev/null +++ b/recipes/userver/all/test_package/test_mongo.cpp @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hello.hpp" + +int main(int argc, char* argv[]) { + auto component_list = userver::components::MinimalServerComponentList() + .Append() + .Append() + .Append() + .Append() + .Append(""); + + service_template::AppendHello(component_list); + + auto size = std::distance(component_list.begin(), component_list.end()); + std::cout << size << std::endl; + + return 0; +} diff --git a/recipes/userver/all/test_package/test_postgresql.cpp b/recipes/userver/all/test_package/test_postgresql.cpp new file mode 100644 index 00000000000000..f630e06ff15992 --- /dev/null +++ b/recipes/userver/all/test_package/test_postgresql.cpp @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hello.hpp" + +int main(int argc, char* argv[]) { + auto component_list = userver::components::MinimalServerComponentList() + .Append() + .Append() + .Append() + .Append() + .Append(""); + + service_template::AppendHello(component_list); + + auto size = std::distance(component_list.begin(), component_list.end()); + std::cout << size << std::endl; + + return 0; +} diff --git a/recipes/userver/all/test_package/test_rabbitmq.cpp b/recipes/userver/all/test_package/test_rabbitmq.cpp new file mode 100644 index 00000000000000..7e0e714dad4063 --- /dev/null +++ b/recipes/userver/all/test_package/test_rabbitmq.cpp @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hello.hpp" + +int main(int argc, char* argv[]) { + auto component_list = userver::components::MinimalServerComponentList() + .Append() + .Append() + .Append() + .Append() + .Append(""); + + service_template::AppendHello(component_list); + + auto size = std::distance(component_list.begin(), component_list.end()); + std::cout << size << std::endl; + + return 0; +} diff --git a/recipes/userver/all/test_package/test_redis.cpp b/recipes/userver/all/test_package/test_redis.cpp new file mode 100644 index 00000000000000..b7cd0579e3b142 --- /dev/null +++ b/recipes/userver/all/test_package/test_redis.cpp @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hello.hpp" + +int main(int argc, char* argv[]) { + auto component_list = userver::components::MinimalServerComponentList() + .Append() + .Append() + .Append() + .Append() + .Append(""); + + service_template::AppendHello(component_list); + + auto size = std::distance(component_list.begin(), component_list.end()); + std::cout << size << std::endl; + + return 0; +} diff --git a/recipes/userver/all/test_package/test_ubench.cpp b/recipes/userver/all/test_package/test_ubench.cpp new file mode 100644 index 00000000000000..528d5778e942f2 --- /dev/null +++ b/recipes/userver/all/test_package/test_ubench.cpp @@ -0,0 +1,23 @@ +#include "hello.hpp" + +#include // for std::uint64_t +#include // for std::size +#include + +#include +#include + +void HelloBenchmark(benchmark::State& state) { + userver::engine::RunStandalone([&] { + constexpr std::string_view kNames[] = {"userver", "is", "awesome", "!"}; + std::uint64_t i = 0; + + for (auto _ : state) { + const auto name = kNames[i++ % std::size(kNames)]; + auto result = service_template::SayHelloTo(name); + benchmark::DoNotOptimize(result); + } + }); +} + +BENCHMARK(HelloBenchmark); diff --git a/recipes/userver/all/test_package/test_universal.cpp b/recipes/userver/all/test_package/test_universal.cpp new file mode 100644 index 00000000000000..9fcc6380ee8ddd --- /dev/null +++ b/recipes/userver/all/test_package/test_universal.cpp @@ -0,0 +1,11 @@ +#include +#include + +#include + +int main() { + auto json = userver::formats::json::FromString(R"({ + "test": "hello from universal" + })"); + std::cout << userver::formats::json::ToString(json) << std::endl; +} diff --git a/recipes/userver/all/test_package/test_utest.cpp b/recipes/userver/all/test_package/test_utest.cpp new file mode 100644 index 00000000000000..68186dfde23b22 --- /dev/null +++ b/recipes/userver/all/test_package/test_utest.cpp @@ -0,0 +1,8 @@ +#include "hello.hpp" + +#include + +UTEST(SayHelloTo, Basic) { + EXPECT_EQ(service_template::SayHelloTo("Developer"), "Hello, Developer!\n"); + EXPECT_EQ(service_template::SayHelloTo({}), "Hello, unknown user!\n"); +} diff --git a/recipes/userver/config.yml b/recipes/userver/config.yml new file mode 100644 index 00000000000000..0c9f31e41743a6 --- /dev/null +++ b/recipes/userver/config.yml @@ -0,0 +1,3 @@ +versions: + "cci.20231018": + folder: all