Files
vdm/core/tests/CMakeLists.txt
T
samiandClaude Sonnet 5 91636f8a4d core: add the download engine — task machine, DownloadHandle, Engine
Stage 8 of the CORE build order: the bodies behind the DownloadSpec /
callback API reviewed in core/docs/engine-api-m1.md. Wires probe -> segment
workers -> WriteBuffer -> SparseFile -> .veloxpart.meta -> retry/backoff ->
SegmentBudget -> RateLimiter -> callbacks into one event-driven machine.

- Engine (src/engine.cpp): owns HttpClient, Prober, SegmentBudget,
  RateLimiter and one timer jthread (min-heap of scheduled fns). start()
  builds a task and returns a DownloadHandle; ~Impl quiesces every task
  before joining the timer so no callback fires during teardown.

- DownloadTaskState (src/task/download_task.cpp): one `mu` task lock; a
  shared_mutex over the worker map for the curl write path; callbacks
  collected under `mu` and fired after release via a separate deferred
  queue; weak_from_this() in every async hop. State machine over the
  CORE-owned EngineState subset, auto-pause on 401/407 and on a 200 where
  206 was expected, validated resume via If-Range.

- digest (src/task/digest.cpp): OpenSSL EVP hash_file() for the optional
  post-download checksum; links OpenSSL::Crypto PRIVATE.

- Segmenter::release_segment(): hand a paused segment back to the pool
  unassigned so resume's assign_slot() picks it up instead of splitting a
  still-"assigned" range and orphaning its front half.

- DownloadHandle now names the real control block (vdm::task::
  DownloadTaskState, defined only in the engine TU) via a namespace-scope
  fwd decl and a public-but-effectively-engine-only ctor, replacing the
  nested State/friend pair. Every public signature is unchanged; DAEMON
  (vdm-79) confirmed sched/ names only the public API.

Fixes found while building the end-to-end suite (tests/task/engine_test.cpp,
9 cases against tools/testserver, green under ASan/UBSan and TSan):
- a dropped connection lost its unflushed WriteBuffer tail while advance()
  had already counted those bytes as done -> a retry resumed past an
  unwritten hole. Flush on the failure path.
- when the byte counters hit total while other workers were still live,
  teardown dropped their buffered tails. Now: cancel them and let each
  worker's own seg_finished drain it (the `assembling` state), last one
  starts verification -- no cross-thread buffer access.
- seg_head() let a 401 with credentials present abort before libcurl's
  resend; now it proceeds once and acts on the final status.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HPPSGhiArbvQgwC2DNiURS
2026-09-10 20:19:31 +04:00

58 lines
2.8 KiB
CMake

# CORE unit tests.
#
# Harness is the provisional header-only vtest (support/vtest.hpp); PKG owns the final
# framework choice (core/docs/pkg-requests-m1.md P2). vdm_add_test() is the only thing
# test files touch, so swapping harnesses is a one-function edit.
add_library(vtest_main STATIC support/vtest_main.cpp)
target_include_directories(vtest_main PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/support)
target_compile_features(vtest_main PUBLIC cxx_std_23)
function(vdm_add_test name)
add_executable(${name} ${ARGN})
target_link_libraries(${name} PRIVATE veloxcore vtest_main)
target_compile_options(${name} PRIVATE -Wall -Wextra -Wpedantic -Werror)
add_test(NAME ${name} COMMAND ${name})
endfunction()
vdm_add_test(veloxcore_result_test util/result_test.cpp)
vdm_add_test(veloxcore_event_bus_test util/event_bus_test.cpp)
vdm_add_test(veloxcore_thread_pool_test util/thread_pool_test.cpp)
vdm_add_test(veloxcore_bytes_test util/bytes_test.cpp)
vdm_add_test(veloxcore_log_test util/log_test.cpp)
# net/ integration tests drive tools/testserver (lane PKG/QA). Skip cleanly if it isn't
# in the tree yet (lanes merge independently).
vdm_add_test(veloxcore_content_disposition_test net/content_disposition_test.cpp)
vdm_add_test(veloxcore_url_test net/url_test.cpp)
vdm_add_test(veloxcore_sparse_file_test io/sparse_file_test.cpp)
vdm_add_test(veloxcore_write_buffer_test io/write_buffer_test.cpp)
vdm_add_test(veloxcore_veloxpart_test meta/veloxpart_test.cpp)
vdm_add_test(veloxcore_segmenter_test segment/segmenter_test.cpp)
vdm_add_test(veloxcore_budget_test segment/budget_test.cpp)
vdm_add_test(veloxcore_engine_api_test task/api_compiles_test.cpp)
vdm_add_test(veloxcore_token_bucket_test rate/token_bucket_test.cpp)
set(_testserver ${CMAKE_SOURCE_DIR}/tools/testserver/testserver.py)
vdm_add_test(veloxcore_engine_test task/engine_test.cpp)
target_include_directories(veloxcore_engine_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/net ${CMAKE_SOURCE_DIR}/core/src)
if(EXISTS ${_testserver})
target_compile_definitions(veloxcore_engine_test PRIVATE VDM_TESTSERVER_PY="${_testserver}")
set_tests_properties(veloxcore_engine_test PROPERTIES TIMEOUT 300)
endif()
foreach(net_it http_client probe)
vdm_add_test(veloxcore_${net_it}_test net/${net_it}_test.cpp)
target_include_directories(veloxcore_${net_it}_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/net)
if(EXISTS ${_testserver})
target_compile_definitions(veloxcore_${net_it}_test
PRIVATE VDM_TESTSERVER_PY="${_testserver}")
set_tests_properties(veloxcore_${net_it}_test PROPERTIES TIMEOUT 120)
endif()
endforeach()
if(NOT EXISTS ${_testserver})
message(STATUS "veloxcore: tools/testserver not present; net integration tests will "
"skip their server-backed cases.")
endif()