Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .github/workflows/lint-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,3 @@ permissions:
jobs:
lint-and-test:
uses: esclient/tools/.github/workflows/lint-and-test-cpp.yml@main
with:
sonar-inclusions: "src/**,tests/**"
sonar-exclusions: "**/generated/**,**/grpc/**,tests/mocks/**,tests/unit/**"
sonar-coverage-exclusions: "tests/mocks/**,tests/unit/**,src/moderationservice/main.cpp,src/moderationservice/server/server.cpp"
secrets:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
65 changes: 33 additions & 32 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.20)
project(moderation-service)
enable_testing()
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)

if(MSVC)
add_compile_options(/utf-8)
Expand Down Expand Up @@ -94,10 +94,9 @@ target_include_directories(${GENPROTO_LIB} PUBLIC ${GENPROTO_DIR})

target_link_libraries(${GENPROTO_LIB} PUBLIC protobuf::libprotobuf gRPC::grpc++ abseil::abseil)

# link source files
add_executable(
${PROJECT_NAME}
src/moderationservice/main.cpp
# Shared service implementation (everything except the process entrypoint)
add_library(
moderation_core STATIC
src/moderationservice/server/server.cpp
src/moderationservice/service/service.cpp
src/moderationservice/handler/handler.cpp
Expand All @@ -110,26 +109,40 @@ add_executable(
src/moderationservice/kafka/kafkaclient.cpp
src/moderationservice/model/model_utils.cpp)

target_include_directories(
moderation_core
PUBLIC ${PROJECT_SOURCE_DIR}/include
${PROJECT_SOURCE_DIR}/src/moderationservice
${PROJECT_SOURCE_DIR}/src/moderationservice/repository
${PROJECT_SOURCE_DIR}/src/moderationservice/handler
${PROJECT_SOURCE_DIR}/src/moderationservice/service
${PROJECT_SOURCE_DIR}/src/moderationservice/model
${PROJECT_SOURCE_DIR}/src/moderationservice/kafka
${GENPROTO_DIR})

target_link_libraries(
${PROJECT_NAME}
PRIVATE ${GENPROTO_LIB}
gRPC::grpc++
gRPC::grpc++_reflection
protobuf::libprotobuf
ICU::uc
ICU::i18n
ICU::data
tsl::hat_trie
Threads::Threads
RdKafka::rdkafka
RdKafka::rdkafka++
libpqxx::pqxx
abseil::abseil)
moderation_core
PUBLIC ${GENPROTO_LIB}
gRPC::grpc++
gRPC::grpc++_reflection
protobuf::libprotobuf
ICU::uc
ICU::i18n
ICU::data
tsl::hat_trie
Threads::Threads
RdKafka::rdkafka
RdKafka::rdkafka++
libpqxx::pqxx
abseil::abseil)

if(WIN32)
target_compile_definitions(${PROJECT_NAME} PRIVATE U_STATIC_IMPLEMENTATION)
target_compile_definitions(moderation_core PRIVATE U_STATIC_IMPLEMENTATION)
endif()

add_executable(${PROJECT_NAME} src/moderationservice/main.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE moderation_core)

set(PROJECT_SOURCE_DIRS ${PROJECT_SOURCE_DIR}/src/moderationservice ${PROJECT_SOURCE_DIR}/include
${PROJECT_SOURCE_DIR}/tests ${PROJECT_SOURCE_DIR}/benchmark)

Expand Down Expand Up @@ -293,18 +306,6 @@ set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH ${_OLD_CMAKE_FIND_USE_SYSTEM_ENVIRONM
# END LINTING SECTION
# ============================================================================

# link header files
target_include_directories(
${PROJECT_NAME}
PUBLIC ${PROJECT_SOURCE_DIR}/include
PRIVATE ${PROJECT_SOURCE_DIR}/src/moderationservice
${PROJECT_SOURCE_DIR}/src/moderationservice/repository
${PROJECT_SOURCE_DIR}/src/moderationservice/handler
${PROJECT_SOURCE_DIR}/src/moderationservice/service
${PROJECT_SOURCE_DIR}/src/moderationservice/model
${PROJECT_SOURCE_DIR}/src/moderationservice/kafka
${GENPROTO_DIR})

add_subdirectory(tests)

option(BUILD_BENCHMARKS "Build benchmark executables" OFF)
Expand Down
13 changes: 3 additions & 10 deletions benchmark/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,12 @@ find_package(benchmark REQUIRED CONFIG)
add_executable(
text_processing_benchmark
performance/text_processing_benchmark.cpp
${PROJECT_SOURCE_DIR}/src/moderationservice/service/text_processor.cpp
${PROJECT_SOURCE_DIR}/src/moderationservice/service/text_normalization.cpp
${PROJECT_SOURCE_DIR}/src/moderationservice/service/leetspeak_normalization.cpp
${PROJECT_SOURCE_DIR}/src/moderationservice/service/word_checker.cpp
${PROJECT_SOURCE_DIR}/src/moderationservice/model/constants.cpp
)

target_include_directories(
target_link_libraries(
text_processing_benchmark
PRIVATE
${CMAKE_SOURCE_DIR}/src/moderationservice
${CMAKE_SOURCE_DIR}/include
${CMAKE_BINARY_DIR}/generated/grpc
benchmark::benchmark
moderation_core
)

target_link_libraries(
Expand Down
3 changes: 3 additions & 0 deletions conanfile.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,6 @@
librdkafka/*:sasl=True
benchmark/*:shared=False
benchmark/*:enable_lto=True
protobuf/*:shared=False
icu/*:shared=False

6 changes: 4 additions & 2 deletions src/moderationservice/kafka/kafkaclient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,15 +196,17 @@ void KafkaConsumer::ProcessMessage(RdKafka::Message* message) {
std::string key_str(key_ptr, message->key_len());

// Validate that key_str contains only digits (and optional leading +/-)
if (key_str.empty() || (!std::isdigit(key_str[0]) && key_str[0] != '-' && key_str[0] != '+')) {
if (key_str.empty() ||
(!std::isdigit(key_str[0]) && key_str[0] != '-' && key_str[0] != '+')) {
std::cerr << "Invalid message key format (not numeric): '" << key_str << "'\n";
return;
}

try {
request_id = std::stoll(key_str);
} catch (const std::exception& e) {
std::cerr << "Failed to parse message key '" << key_str << "' to request ID: " << e.what() << "\n";
std::cerr << "Failed to parse message key '" << key_str
<< "' to request ID: " << e.what() << "\n";
return;
}
}
Expand Down
39 changes: 8 additions & 31 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,38 +12,20 @@ set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)

set(TEST_DEPS
genproto_lib
Threads::Threads
)

set(SERVICE_TEST_SOURCES
${CMAKE_SOURCE_DIR}/src/moderationservice/service/text_normalization.cpp
${CMAKE_SOURCE_DIR}/src/moderationservice/service/leetspeak_normalization.cpp
${CMAKE_SOURCE_DIR}/src/moderationservice/service/word_checker.cpp
${CMAKE_SOURCE_DIR}/src/moderationservice/service/text_processor.cpp
${CMAKE_SOURCE_DIR}/src/moderationservice/model/constants.cpp
${CMAKE_SOURCE_DIR}/src/moderationservice/model/model_utils.cpp
)

function(add_service_test TEST_NAME)
add_executable(${TEST_NAME} ${ARGN} ${SERVICE_TEST_SOURCES})

add_executable(${TEST_NAME} ${ARGN})
target_include_directories(${TEST_NAME} PRIVATE
${CMAKE_SOURCE_DIR}/src/moderationservice
${CMAKE_SOURCE_DIR}/include
${CMAKE_SOURCE_DIR}/tests
${GENPROTO_DIR}
${CMAKE_SOURCE_DIR}/src/moderationservice
${CMAKE_SOURCE_DIR}/include
${CMAKE_SOURCE_DIR}/tests
${GENPROTO_DIR}
)

target_link_libraries(${TEST_NAME} PRIVATE
GTest::gtest_main
${GENPROTO_LIB}
ICU::uc ICU::i18n
ICU::data
tsl::hat_trie
libpqxx::pqxx
RdKafka::rdkafka
RdKafka::rdkafka++
target_link_libraries(${TEST_NAME} PRIVATE
GTest::gtest_main
moderation_core
${TEST_DEPS}
)
gtest_discover_tests(${TEST_NAME} DISCOVERY_MODE PRE_TEST)
Expand Down Expand Up @@ -71,18 +53,13 @@ add_service_test(text_processor_test

add_service_test(moderation_service_test
${CMAKE_CURRENT_SOURCE_DIR}/unit/service/moderation_service_test.cpp
${CMAKE_SOURCE_DIR}/src/moderationservice/service/service.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mocks/fake_moderation_repository.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mocks/mock_kafka_client.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mocks/test_utils.cpp
${CMAKE_SOURCE_DIR}/src/moderationservice/kafka/kafkaclient.cpp
)

add_service_test(handler_test
${CMAKE_CURRENT_SOURCE_DIR}/unit/handler/handler_test.cpp
${CMAKE_SOURCE_DIR}/src/moderationservice/handler/handler.cpp
${CMAKE_SOURCE_DIR}/src/moderationservice/service/service.cpp
${CMAKE_SOURCE_DIR}/src/moderationservice/kafka/kafkaclient.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mocks/fake_moderation_repository.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mocks/mock_kafka_client.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mocks/test_utils.cpp
Expand Down
62 changes: 37 additions & 25 deletions tools/common.just
Original file line number Diff line number Diff line change
Expand Up @@ -5,65 +5,72 @@ DOWN_OUT := '-o'
EXE := if os() == "windows" { ".exe" } else { "" }
TEST_DIR := if os() == "windows" { "./build/tests/Release" } else { "./build/tests" }

CACHE_TOOL := `which sccache 2>/dev/null || which ccache 2>/dev/null || echo ""`

# Parallel jobs for Linux (nproc with getconf fallback)
JOBS := if os() == "windows" { "" } else { `nproc 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || echo 4` }
PARALLEL := if os() == "windows" { "" } else { "-j" + JOBS }

fetch-proto:
{{MKDIR}} "{{TMP_DIR}}"
{{DOWN}} "https://raw.githubusercontent.com/esclient/protos/{{PROTO_TAG}}/{{PROTO_NAME}}" {{DOWN_OUT}} "{{TMP_DIR}}/{{PROTO_NAME}}"

build-linux: fetch-proto
conan install . --output-folder=build --build=missing
conan install . --output-folder=build --build=missing --settings compiler.cppstd=20
cmake -S . -B build \
-DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release
-DCMAKE_BUILD_TYPE=Release \
{{ if CACHE_TOOL != "" { "-DCMAKE_C_COMPILER_LAUNCHER=" + CACHE_TOOL + " -DCMAKE_CXX_COMPILER_LAUNCHER=" + CACHE_TOOL } else { "" } }}
cmake --build build --config Release -- {{PARALLEL}}

build-windows: fetch-proto
conan install . --output-folder=build --build=missing
conan install . --output-folder=build --build=missing --settings compiler.cppstd=20
cmake -S . -B build \
-G "Visual Studio 17 2022" \
-A x64 \
-DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release

kafka-container-up:
docker-compose up -d
MSYS_NO_PATHCONV=1 docker exec kafka /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --create --topic moderation-result --replication-factor 1 --partitions 3 || true
MSYS_NO_PATHCONV=1 docker exec kafka /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --create --topic moderation-request --replication-factor 1 --partitions 3 || true

kafka-container-down:
MSYS_NO_PATHCONV=1 docker exec kafka /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --delete --topic moderation-request
MSYS_NO_PATHCONV=1 docker exec kafka /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --delete --topic moderation-result
docker-compose down -vv

configure-lint: fetch-proto
conan install . --output-folder=build-lint --build=missing -c tools.cmake.cmaketoolchain:generator=Ninja
cmake -S . -B build-lint \
-G "Ninja" \
-DCMAKE_TOOLCHAIN_FILE=build-lint/conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DENABLE_CLANG_TIDY=ON
-DENABLE_CLANG_TIDY=ON \
{{ if CACHE_TOOL != "" { "-DCMAKE_C_COMPILER_LAUNCHER=" + CACHE_TOOL + " -DCMAKE_CXX_COMPILER_LAUNCHER=" + CACHE_TOOL } else { "" } }}

format:
cmake --build build-lint --target clang-format
cmake --build build-lint --target clang-format -- {{PARALLEL}}
cmake --build build-lint --target cmake-format

clean-lint:
rm -rf build-lint

lint-all-linux:
just configure-lint
just format
cmake --build build-lint
cmake --build build-lint --target lint-all
cmake --build build-lint -- {{PARALLEL}}
cmake --build build-lint --target lint-all -- {{PARALLEL}}

kafka-container-up:
docker-compose up -d
sleep 10
MSYS_NO_PATHCONV=1 docker exec kafka /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --create --topic moderation-result --replication-factor 1 --partitions 3
MSYS_NO_PATHCONV=1 docker exec kafka /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --create --topic moderation-request --replication-factor 1 --partitions 3

kafka-container-down:
MSYS_NO_PATHCONV=1 docker exec kafka /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --delete --topic moderation-request
MSYS_NO_PATHCONV=1 docker exec kafka /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --delete --topic moderation-result
docker-compose down -vv

clean-lint:
rm -rf build-lint

run-l:
just kafka-container-up
just build-linux
ENV=dev tools/load_envs.sh ./build/moderation-service

run-w:
just kafka-container-up
run-w:
just build-windows
ENV=dev tools/load_envs.sh ./build/Release/moderation-service.exe

Expand All @@ -75,6 +82,11 @@ check-dev-tools:
@which cpplint >/dev/null 2>&1 && echo "[OK] cpplint" || echo "[X] cpplint"
@which cmake-format >/dev/null 2>&1 && echo "[OK] cmake-format" || echo "[X] cmake-format"
@which pipx >/dev/null 2>&1 && echo "[OK] pipx" || echo "[X] pipx"
@echo ""
@echo "Checking compiler cache:"
@which sccache >/dev/null 2>&1 && echo "[OK] sccache (preferred)" || echo "[X] sccache"
@which ccache >/dev/null 2>&1 && echo "[OK] ccache (fallback)" || echo "[X] ccache"
@echo "Active cache tool: {{CACHE_TOOL}}"

install-dev-tools:
chmod +x ./tools/install_dev_tools.sh
Expand All @@ -99,4 +111,4 @@ benchmark:
cmake --build build --target text_processing_benchmark --config Release
cmake --build build --target text_processing_benchmark --config Release && \
(./build/benchmark/Release/text_processing_benchmark.exe || \
./build/benchmark/text_processing_benchmark)
./build/benchmark/text_processing_benchmark)
Loading