pcloudcc-lneely/tests/unit-tests/test_pfs_helpers.c

245 lines
9.4 KiB
C

/*
* Test: pfs_helpers.c — row→stat converters and task overlay
*
* Covers:
* 1. pfs_row_to_folder_stat: st_ino, st_mode, st_nlink, st_mtime populated
* from the variant row; st_uid/gid come from pfs_stat_uid/gid globals.
* 2. pfs_row_to_file_stat: st_ino, st_mode, st_size, st_ctime populated
* (non-encrypted path, flags=0).
* 3. pfs_apply_task_overlay: mkdir pending → stat filled as dir;
* rmdir pending → -1; no overlay → 0.
* 4. pfs_fldr_resolve_path weak override: replacement injects a fake path
* without a FUSE mount or psql connection.
*/
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include "pfs_helpers.h"
#include "pfstasks_tree.h" /* pfs_task_insert_into_tree, pfs_task_find_* */
#include "plibs.h" /* PSYNC_TNUMBER, psync_variant */
/* ------------------------------------------------------------------ */
/* --wrap stubs: pfs_task_get_folder_tasks_rdlocked, pfs_crpt_plain_size,
* ptimer_time — none of these should be called in the pure-tree / non-
* encrypted test paths; return safe no-op values just in case. */
psync_fstask_folder_t *__wrap_pfs_task_get_folder_tasks_rdlocked(
psync_fsfolderid_t folderid) {
(void)folderid;
return NULL; /* no in-memory mtime override in tests */
}
uint64_t __wrap_pfs_crpt_plain_size(uint64_t cryptosize) {
return cryptosize; /* identity for non-encrypted tests */
}
time_t __wrap_ptimer_time(void) {
return 9999; /* fixed timestamp for deterministic tests */
}
/* ------------------------------------------------------------------ */
static int passes = 0, failures = 0;
#define PASS(n) do { printf("PASS: %s\n", n); passes++; } while (0)
#define FAIL(n, ...) do { printf("FAIL: %s — ", n); printf(__VA_ARGS__); printf("\n"); failures++; } while (0)
/* ------------------------------------------------------------------ */
/* Helper: build a psync_variant holding a uint64_t number */
/* ------------------------------------------------------------------ */
static psync_variant mknum(uint64_t v) {
psync_variant pv;
memset(&pv, 0, sizeof(pv));
pv.type = PSYNC_TNUMBER;
pv.num = v;
return pv;
}
/* ------------------------------------------------------------------ */
/* Test 1: pfs_row_to_folder_stat */
/* ------------------------------------------------------------------ */
static void test_folder_stat(void) {
/*
* Folder row layout: [0]=id [1]=permissions [2]=ctime [3]=mtime [4]=subdircnt
*/
psync_variant row[5];
row[0] = mknum(100); /* folderid = 100 */
row[1] = mknum(0755); /* permissions */
row[2] = mknum(1000); /* ctime */
row[3] = mknum(2000); /* mtime */
row[4] = mknum(3); /* subdircnt = 3 → nlink = 5 */
struct stat st;
memset(&st, 0, sizeof(st));
pfs_row_to_folder_stat(row, &st);
if (st.st_ino != PFS_FOLDERID_TO_INODE(100))
FAIL("folder_stat: st_ino", "expected %lu got %lu",
(unsigned long)PFS_FOLDERID_TO_INODE(100), (unsigned long)st.st_ino);
else if (!S_ISDIR(st.st_mode))
FAIL("folder_stat: S_ISDIR", "mode=0%o", (unsigned)st.st_mode);
else if (st.st_nlink != 5)
FAIL("folder_stat: st_nlink", "expected 5 got %lu", (unsigned long)st.st_nlink);
else if (st.st_mtime != 2000)
FAIL("folder_stat: st_mtime", "expected 2000 got %ld", (long)st.st_mtime);
else if (st.st_uid != pfs_stat_uid || st.st_gid != pfs_stat_gid)
FAIL("folder_stat: uid/gid", "uid=%d gid=%d",
(int)st.st_uid, (int)st.st_gid);
else
PASS("pfs_row_to_folder_stat: ino/mode/nlink/mtime/uid/gid correct");
}
/* ------------------------------------------------------------------ */
/* Test 2: pfs_row_to_file_stat (non-encrypted, flags=0) */
/* ------------------------------------------------------------------ */
static void test_file_stat(void) {
/*
* File row layout: [0]=name [1]=size [2]=ctime [3]=mtime [4]=id
*/
psync_variant row[5];
row[0] = mknum(0); /* name (unused in stat) */
row[1] = mknum(4096); /* size = 4096 bytes */
row[2] = mknum(3000); /* ctime */
row[3] = mknum(3000); /* mtime */
row[4] = mknum(77); /* fileid = 77 */
struct stat st;
memset(&st, 0, sizeof(st));
pfs_row_to_file_stat(row, &st, 0 /* non-encrypted */);
if (st.st_ino != PFS_FILEID_TO_INODE(77))
FAIL("file_stat: st_ino", "expected %lu got %lu",
(unsigned long)PFS_FILEID_TO_INODE(77), (unsigned long)st.st_ino);
else if (!S_ISREG(st.st_mode))
FAIL("file_stat: S_ISREG", "mode=0%o", (unsigned)st.st_mode);
else if (st.st_size != 4096)
FAIL("file_stat: st_size", "expected 4096 got %ld", (long)st.st_size);
else if (st.st_ctime != 3000)
FAIL("file_stat: st_ctime", "expected 3000 got %ld", (long)st.st_ctime);
else if (st.st_nlink != 1)
FAIL("file_stat: st_nlink", "expected 1 got %lu", (unsigned long)st.st_nlink);
else
PASS("pfs_row_to_file_stat: ino/mode/size/ctime/nlink correct");
}
/* ------------------------------------------------------------------ */
/* Test 3: pfs_apply_task_overlay */
/* ------------------------------------------------------------------ */
/* Helper: allocate a psync_fstask_mkdir_t and insert it into folder */
static psync_fstask_mkdir_t *make_mkdir(psync_fstask_folder_t *f,
const char *name,
uint64_t taskid,
psync_fsfolderid_t folderid) {
size_t len = strlen(name) + 1;
psync_fstask_mkdir_t *mk = (psync_fstask_mkdir_t *)
calloc(1, offsetof(psync_fstask_mkdir_t, name) + len);
mk->taskid = taskid;
mk->folderid = folderid;
mk->mtime = 5000;
mk->flags = 0;
memcpy(mk->name, name, len);
pfs_task_insert_into_tree(&f->mkdirs, offsetof(psync_fstask_mkdir_t, name),
&mk->tree);
return mk;
}
static psync_fstask_rmdir_t *make_rmdir(psync_fstask_folder_t *f,
const char *name,
uint64_t taskid) {
size_t len = strlen(name) + 1;
psync_fstask_rmdir_t *rm = (psync_fstask_rmdir_t *)
calloc(1, offsetof(psync_fstask_rmdir_t, name) + len);
rm->taskid = taskid;
memcpy(rm->name, name, len);
pfs_task_insert_into_tree(&f->rmdirs, offsetof(psync_fstask_rmdir_t, name),
&rm->tree);
return rm;
}
static void test_apply_task_overlay(void) {
/* NULL folder → 0 */
struct stat st;
int rc = pfs_apply_task_overlay(&st, NULL, "any", 0);
if (rc != 0)
{ FAIL("overlay NULL folder", "expected 0 got %d", rc); }
else
PASS("pfs_apply_task_overlay: NULL folder returns 0");
/* mkdir pending → 1, stbuf filled as directory */
psync_fstask_folder_t f;
memset(&f, 0, sizeof(f));
f.folderid = 200;
psync_fstask_mkdir_t *mk = make_mkdir(&f, "newdir", 10, -10);
memset(&st, 0, sizeof(st));
rc = pfs_apply_task_overlay(&st, &f, "newdir", 0);
if (rc != 1)
FAIL("overlay mkdir: rc=1", "got %d", rc);
else if (!S_ISDIR(st.st_mode))
FAIL("overlay mkdir: S_ISDIR", "mode=0%o", (unsigned)st.st_mode);
else
PASS("pfs_apply_task_overlay: mkdir pending → rc=1, stbuf is a dir");
/* rmdir pending → -1 */
psync_fstask_rmdir_t *rm = make_rmdir(&f, "olddir", 20);
memset(&st, 0, sizeof(st));
rc = pfs_apply_task_overlay(&st, &f, "olddir", 0);
if (rc != -1)
FAIL("overlay rmdir: rc=-1", "got %d", rc);
else
PASS("pfs_apply_task_overlay: rmdir pending → rc=-1 (ENOENT)");
/* no overlay for absent name → 0 */
rc = pfs_apply_task_overlay(&st, &f, "noentry", 0);
if (rc != 0)
FAIL("overlay no match: rc=0", "got %d", rc);
else
PASS("pfs_apply_task_overlay: no pending task for name → rc=0");
free(mk); free(rm);
}
/* ------------------------------------------------------------------ */
/* Test 4: pfs_fldr_resolve_path weak override */
/* ------------------------------------------------------------------ */
static psync_fspath_t g_fake_path;
static int g_resolve_called = 0;
psync_fspath_t *pfs_fldr_resolve_path(const char *path) {
(void)path;
g_resolve_called++;
return &g_fake_path;
}
static void test_resolve_path_override(void) {
g_resolve_called = 0;
memset(&g_fake_path, 0, sizeof(g_fake_path));
g_fake_path.folderid = 999;
psync_fspath_t *r = pfs_fldr_resolve_path("/test/path");
if (!r || r->folderid != 999)
FAIL("resolve override: returns fake path", "folderid=%lld",
r ? (long long)r->folderid : -1LL);
else if (g_resolve_called != 1)
FAIL("resolve override: called once", "called=%d", g_resolve_called);
else
PASS("pfs_fldr_resolve_path: weak override injects fake path");
}
/* ------------------------------------------------------------------ */
int main(void) {
/* tests use uid/gid = 0 (default from pfs_helpers.c init) */
test_folder_stat();
test_file_stat();
test_apply_task_overlay();
test_resolve_path_override();
printf("\n%d passed, %d failed\n", passes, failures);
return failures ? 1 : 0;
}