Commit Graph

9 Commits

Author SHA1 Message Date
Levi Neely 82aaf83d9a Implement Tasks #3, #4, #5: tree tests, pfstasks tree layer, DB harness
Task #3 — Unit tests for ptree and pintervaltree
  tests/unit-tests/test_ptree.c: 8 tests covering single-node insert,
  in-order traversal after arbitrary and reverse inserts, BST lookup,
  leaf/root/all-node deletion, and ptree_for_each visitation.
  tests/unit-tests/test_pintervaltree.c: 18 tests covering single add,
  non-overlapping, overlapping/adjacent/contained/spanning merges,
  chain merge, remove middle split, remove exact/left/right/spanning,
  cut_end, first_interval_containing_or_after, and free(NULL).

Task #4 — Extract pfstasks tree layer
  pclsync/pfstasks_tree.h + pclsync/pfstasks_tree.c: pure tree layer
  (zero psql calls) extracted from pfstasks.c — pfs_task_search_tree,
  pfs_task_walk_tree (static helpers), pfs_task_insert_into_tree,
  pfs_task_find_mkdir/rmdir/creat/unlink,
  pfs_task_find_mkdir_by_folderid, pfs_task_find_creat_by_fileid.
  pclsync/pfstasks.c: #includes pfstasks_tree.h; all moved functions
  removed; all callers unchanged.
  tests/unit-tests/test_pfstasks_tree.c: 13 tests using direct tree
  construction (no DB) to verify find-by-name, taskid discrimination,
  find-by-numeric-id, and empty-folder edge cases.

Task #5 — psql in-memory harness + pfstasks DB tests
  tests/helpers/psql_test_helpers.h + .c: lightweight harness that
  opens :memory: via sqlite3_open, enables PRAGMA foreign_keys=ON, and
  applies the full PSYNC_DATABASE_STRUCTURE schema. Exposes
  psql_test_db(), psql_test_exec(), psql_test_insert_fstask(),
  psql_test_count_fstask/fstaskdepend(). No dependency on psql.c.
  tests/unit-tests/test_pfstasks_db.c: 10 tests verifying schema
  creation, fstask insertion/query, fstaskdepend insertion, CASCADE
  DELETE propagation, FK enforcement, rmdir-blocking SQL pattern,
  creat-after-unlink sequencing, and open/close idempotence.

All 11 new tests pass; production build clean.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 19:48:22 +01:00
Levi Neely 67c99c5e06 Refactor test_ptask_free to link production code via --wrap
Extract psync_task_free + psync_task_destroy (and their static helpers
psync_task_dec_refcnt, psync_task_entry) from ptask.c into a new
separately-compilable unit pclsync/ptask_free.c. Add
pclsync/ptask_free_internal.h to expose the internal struct layout
(struct psync_task_manager_t_ / struct psync_task_t_) for test use
without pulling in ptask.c's heavyweight transitive dependencies.

Rewrite tests/unit-tests/test_ptask_free.c to:
- Include ptask_free_internal.h instead of duplicating structs inline
- Call the real psync_task_free() rather than a local replica
- Intercept pthread_mutex_lock/unlock and pmem_free via --wrap linker
  flags to observe lock discipline and detect destroy invocations

Update the Makefile test_ptask_free target to link pclsync/ptask_free.c
and pass the required --wrap flags. Production build unchanged: ptask_free.o
is picked up automatically by the existing wildcard COBJ rule.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 19:32:05 +01:00
Levi Neely 79a4a5620f
Add GitHub Actions CI workflow for unit tests (#379)
* Add unit test for psync_task_free refcount fix (#377)

Adds tests/unit-tests/test_ptask_free.c to verify all code paths of the
psync_task_free fix from #377: single-owner free, last-ref destroy,
non-last-ref decrement, READY task signaling, and lock-before-refcnt
ordering. All 5 tests pass. Also adds compiled binary to .gitignore.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add GitHub Actions CI workflow for unit tests

Triggers on push/PR to automated-testing branch. Installs cmake and
build-essential, builds all test targets via cmake, and runs ctest
--output-on-failure. Fails workflow on any test failure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Replace cmake CI with make tests/check targets

Adds tests and check targets to Makefile — no cmake required.
Each test binary is built with the correct flags (pthread, -lrt,
--wrap linker flags for prun/ptools_errptr). CI workflow installs
only build-essential, runs make tests then make check; exits non-zero
on any failure. All 8 test suites pass locally.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix CI: install libfuse3-dev so Makefile parses on Ubuntu

detect_fuse.sh runs at Makefile parse time; without fuse headers the
$(error) fires before any target runs. Adding libfuse3-dev unblocks
make tests (test binaries themselves don't link fuse).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix makefile

* Add automated testing infrastructure

- Update CI workflow to run unit tests and build verification
- Add Makefile targets for test compilation and execution
- Implement unit tests for pdbg_path, prun, and read_response
- Add test stubs for pCloud API mocking
- Add test binaries for pfs_lock_ordering and signal_safety verification

* Add missing dependencies to CI workflow

Install libfuse-dev and libssl-dev required for build

* Add test job to c-cpp.yml workflow

Include unit test execution in C/C++ workflow

* Add missing stubs to test_stubs.c

Complete stub implementations for all required pCloud API functions

* Fix stub signatures to match headers

Correct function signatures for pCloud API stubs

* Fix psql_* stub signatures

Correct all psql function signatures to match headers

* Fix stub implementations and Makefile

Update stub functions and build configuration

* Link real utility files instead of stubbing

Update Makefile to use actual implementation files for utilities

* Complete test framework with all 41 tests passing

- Makefile: Add test rules with real dependencies
- tests/stubs/test_stubs.c: Minimal stubs for external APIs
- tests/stubs/test_stubs_cpp.c: Stubs for C++ test
- pclsync/putil.c: Add null check in putil_strdup
- pclsync/pdbg.c: Add recursion guard in pdbg_printf

* Remove duplicate ci.yml workflow

Consolidate CI configuration into c-cpp.yml

* Remove compiled test binaries from git

- Remove test_pfs_lock_ordering and test_signal_safety binaries
- Add tests/test_* to .gitignore to prevent future commits

---------

Co-authored-by: Levi Neely <lkn@darkstar.example.net>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 17:48:42 +01:00
Levi Neely e37c7f5894
Fix pcl-dls: errPtr memory leak between ptools_backend_call() calls in ptools_set_backend_file_dates() (#358)
* Fix pcl-dls.1: free errPtr between calls in ptools_set_backend_file_dates()

char *errPtr was already used instead of char msgErr[1024], but was
not freed between the two ptools_backend_call() invocations. If the
first call allocated errPtr, the second would overwrite the pointer
without freeing it. Add free(errPtr); errPtr = NULL; between the two
calls to eliminate the leak.

Ref GH #194.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add ptools_set_backend_file_dates() errPtr lifecycle tests (pcl-dls)

6 test cases using malloc/free wrapping covering both-succeed,
call1-error, call2-error, both-errors, pre-fix leak demonstration,
and no-double-free after mid-free NULLing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Levi Neely <lkn@darkstar.example.net>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 19:01:17 +01:00
Levi Neely 0430d0b872
Fix pcl-aex: validate PCLOUD_LOG_PATH to prevent arbitrary file write and log injection (#357)
* Fix pcl-aex.1: validate PCLOUD_LOG_PATH before use in psync_debug_path()

Add pdbg_path_is_safe() helper that rejects PCLOUD_LOG_PATH values
that are not absolute, contain '..' path components, or do not resolve
under the user HOME directory or /tmp. On rejection, fall back to the
default ~/.pcloud/debug.log path and emit a warning to stderr.

Also fix a pre-existing memory leak: ppath_home() return was not freed
in the default-path branch.

Ref GH #291.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add PCLOUD_LOG_PATH path-safety tests (pcl-aex)

28 test cases covering relative paths, '..' traversal, paths outside
HOME and /tmp, valid accepted paths, and psync_debug_path() env
fallback behaviour.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Levi Neely <lkn@darkstar.example.net>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 18:53:17 +01:00
Levi Neely 045aad673a
Fix pcl-aqb: pthread_create unchecked return, thread_data leak, and function-pointer cast UB in prun.c (#356)
* Fix pcl-aqb.1: eliminate function-pointer cast UB in start_thread() via union

Replace the single void* run field in thread_data with a union
{ thread0_run run0; thread1_run run1 } so each function pointer is
stored and retrieved at its correct type, eliminating the
thread0_run <-> thread1_run cast chain UB. Split start_thread() into
prun_thread() and prun_thread1() that each populate the appropriate
union member, backed by a shared start_thread_common() helper. Add
malloc NULL check with error log in both public functions.
pthread_create failure handling (log + free) was already present.

Ref GH #199.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add prun start_thread() resource-leak and UB tests (pcl-aqb)

8 test cases using linker interposition covering pthread_create
failure data-free, attr_destroy on failure, malloc failure graceful
return, union fn storage without cast, and success path accounting.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Levi Neely <lkn@darkstar.example.net>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 18:44:47 +01:00
Levi Neely 60e43edec4
Fix pcl-a1j: buffer overflow in ptools_create_backend_event() via unchecked sprintf and strcat (#355)
* Fix pcl-a1j.1: replace sprintf with snprintf and add strcat length check in ptools_create_backend_event()

Add paramname length check (> 254 bytes → skip with warning) before
snprintf into charBuff[i][258], and validate the snprintf return
value. Add explicit length check before strcat into keyParams to
prevent overflow when paramname exceeds remaining buffer space.
Eliminates buffer overflow from long paramname.

Ref GH #195.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix pcl-a1j.1: clamp pCnt to PTOOLS_MAX_PARAMS to prevent charBuff stack overflow

charBuff[30][258] is a fixed-size stack array but pCnt was unbounded,
allowing any caller with params->paramCnt > 30 to overflow the stack
via charBuff[i] access. Add PTOOLS_MAX_PARAMS (30) define, use it to
size charBuff, and clamp pCnt to PTOOLS_MAX_PARAMS with a warning log
before the loop.

Ref GH #195.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add ptools_create_backend_event() validation tests (pcl-a1j)

11 test cases covering pCnt clamping, paramname length guards,
snprintf boundary, keyParams overflow check, and comma-prefix
for subsequent params.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Levi Neely <lkn@darkstar.example.net>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 18:35:43 +01:00
Levi Neely d5a1c74c43
Fix pcl-6nb: readResponse buffer over-read via unchecked msg->length (#354)
* Fix pcl-6nb.1: readResponse buffer over-read in rpcclient.cpp

Replace malloc'd receive buffer with stack array, fix the broken
validation (msg->length compared against POVERLAY_BUFSIZE rather
than max_value_size which excluded the header), fix the payload-read
loop target (msg->length already includes the header, so the old
`header_size + msg->length` limit over-read), add the missing
`msg->length > total_read` guard before memcpy, and add EINTR
handling in the read loop. Eliminates heap over-read when the daemon
sends msg->length > POVERLAY_BUFSIZE.

Ref GH #184.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add readResponse validation tests (pcl-6nb)

Six socketpair-based test cases covering oversized msg->length,
total_read underrun, header underflow, truncated header, valid
message, and exact-boundary acceptance.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Levi Neely <lkn@darkstar.example.net>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 18:08:56 +01:00
Levi Neely 40fd38dde5
Fix pcl-zqv.5.7: eliminate deadlock in pfs_get_both_locks (#339)
* Fix pcl-zqv.5.7: eliminate deadlock in pfs_get_both_locks

- Enforce consistent lock ordering: always acquire psql lock before file mutex
- Remove retry loop that could spin indefinitely
- Replace abort() with error return in pfs_lock_file timeout
- Add unit test verifying lock ordering prevents deadlock

Fixes GH #258

* Reorganize tests: smoke-tests, fault-inject, unit-tests

* Reorganize tests: smoke-tests, fault-inject, unit-tests

* Remove validation report

---------

Co-authored-by: Levi Neely <lkn@darkstar.example.net>
2026-03-03 19:33:56 +01:00