summaryrefslogtreecommitdiff
path: root/tests/test_storage_smoke.c
diff options
context:
space:
mode:
authorinfo@mode42.com <info@mode42.com>2026-08-08 03:54:55 +0000
committerinfo@mode42.com <info@mode42.com>2026-08-08 03:54:55 +0000
commit20cb29c2f8c5c87bc590896854a20b1473ceb358 (patch)
tree2857f41513a56ad41af97b57362639298aa7f033 /tests/test_storage_smoke.c
#2
Diffstat (limited to 'tests/test_storage_smoke.c')
-rw-r--r--tests/test_storage_smoke.c235
1 files changed, 235 insertions, 0 deletions
diff --git a/tests/test_storage_smoke.c b/tests/test_storage_smoke.c
new file mode 100644
index 0000000..77fd3cf
--- /dev/null
+++ b/tests/test_storage_smoke.c
@@ -0,0 +1,235 @@
+/*
+ * test_storage_smoke.c — P0.4: flatfile + SQLite core smoke
+ *
+ * Tests: open/close, register_user, find_user, resolve_user,
+ * count_level, update_user, delete_user, session_begin/end.
+ * Runs against both flatfile and SQLite backends in temporary directories.
+ */
+#include "hybbx/storage.h"
+#include "hybbx/auth.h"
+#include "hybbx/util.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+static unsigned g_failures;
+
+static void check_rc(const char *label, hybbx_result_t got, hybbx_result_t want)
+{
+ if (got != want) {
+ fprintf(stderr, "FAIL %s: got %d want %d\n", label, (int)got, (int)want);
+ g_failures++;
+ }
+}
+
+static void check_str(const char *label, const char *got, const char *want)
+{
+ if (got == NULL || want == NULL || strcmp(got, want) != 0) {
+ fprintf(stderr, "FAIL %s: got '%s' want '%s'\n",
+ label, got != NULL ? got : "(null)", want);
+ g_failures++;
+ }
+}
+
+static void check_uint64(const char *label, uint64_t got, uint64_t want)
+{
+ if (got != want) {
+ fprintf(stderr, "FAIL %s: got %llu want %llu\n",
+ label, (unsigned long long)got, (unsigned long long)want);
+ g_failures++;
+ }
+}
+
+static void check_nonzero(const char *label, uint64_t val)
+{
+ if (val == 0) {
+ fprintf(stderr, "FAIL %s: expected non-zero\n", label);
+ g_failures++;
+ }
+}
+
+static void mkdir_p(const char *path)
+{
+ char tmp[512];
+ char *p;
+ size_t len;
+
+ hybbx_strlcpy(tmp, path, sizeof(tmp));
+ len = strlen(tmp);
+ if (len > 0 && tmp[len - 1] == '/') {
+ tmp[len - 1] = '\0';
+ }
+ for (p = tmp + 1; *p; p++) {
+ if (*p == '/') {
+ *p = '\0';
+ mkdir(tmp, 0755);
+ *p = '/';
+ }
+ }
+ mkdir(tmp, 0755);
+}
+
+static void rm_rf(const char *path)
+{
+ char cmd[512];
+ snprintf(cmd, sizeof(cmd), "rm -rf '%s'", path);
+ (void)system(cmd);
+}
+
+static hybbx_storage_t *open_backend(hybbx_storage_backend_kind_t backend,
+ const char *path)
+{
+ hybbx_storage_options_t opts;
+
+ memset(&opts, 0, sizeof(opts));
+ opts.backend = backend;
+ opts.path = path;
+ return hybbx_storage_open(&opts);
+}
+
+/*
+ * Run the full CRUD + session smoke against one backend.
+ */
+static void smoke_backend(hybbx_storage_backend_kind_t backend,
+ const char *label,
+ const char *path)
+{
+ hybbx_storage_t *st;
+ hybbx_user_registration_t reg;
+ hybbx_user_record_t user;
+ hybbx_user_record_t found;
+ hybbx_session_record_t sess;
+ size_t count;
+ char test_user[64];
+
+ snprintf(test_user, sizeof(test_user), "smk_%s", label);
+
+ rm_rf(path);
+ mkdir_p(path);
+
+ st = open_backend(backend, path);
+ if (st == NULL) {
+ fprintf(stderr, "FAIL %s: storage_open returned NULL\n", label);
+ g_failures++;
+ return;
+ }
+
+ check_uint64("backend kind",
+ (uint64_t)hybbx_storage_backend(st), (uint64_t)backend);
+
+ /* register_user — level defaults to HYBBX_LEVEL_USER */
+ memset(&reg, 0, sizeof(reg));
+ hybbx_strlcpy(reg.username, test_user, sizeof(reg.username));
+ hybbx_strlcpy(reg.password, "testpass123", sizeof(reg.password));
+ hybbx_strlcpy(reg.nickname, test_user, sizeof(reg.nickname));
+ hybbx_strlcpy(reg.full_name, "Smoke Test", sizeof(reg.full_name));
+ hybbx_strlcpy(reg.country, "DE", sizeof(reg.country));
+ hybbx_strlcpy(reg.location, "localhost", sizeof(reg.location));
+ hybbx_strlcpy(reg.email, "smoke@test.local", sizeof(reg.email));
+
+ check_rc("register_user",
+ hybbx_storage_register_user(st, &reg, &user), HYBBX_OK);
+ check_nonzero("user id", user.id);
+ check_str("user username", user.username, test_user);
+ check_uint64("user level", (uint64_t)user.level,
+ (uint64_t)HYBBX_LEVEL_USER);
+
+ /* find_user */
+ memset(&found, 0, sizeof(found));
+ check_rc("find_user",
+ hybbx_storage_find_user(st, test_user, &found), HYBBX_OK);
+ check_uint64("found id matches", found.id, user.id);
+ check_str("found username", found.username, test_user);
+
+ /* find_user nonexistent */
+ check_rc("find_user missing",
+ hybbx_storage_find_user(st, "no_such_user", &found),
+ HYBBX_ERR_NOT_FOUND);
+
+ /* resolve_user (by name) */
+ memset(&found, 0, sizeof(found));
+ check_rc("resolve_user",
+ hybbx_storage_resolve_user(st, test_user, &found), HYBBX_OK);
+ check_uint64("resolve id matches", found.id, user.id);
+
+ /* count_level */
+ count = 0;
+ check_rc("count_level",
+ hybbx_storage_count_level(st, HYBBX_LEVEL_USER, &count),
+ HYBBX_OK);
+ /* count >= 1 (our user) */
+
+ /* update_user */
+ user.level = HYBBX_LEVEL_SYSOP;
+ check_rc("update_user",
+ hybbx_storage_update_user(st, &user), HYBBX_OK);
+
+ memset(&found, 0, sizeof(found));
+ check_rc("find after update",
+ hybbx_storage_find_user(st, test_user, &found), HYBBX_OK);
+ check_uint64("updated level", (uint64_t)found.level,
+ (uint64_t)HYBBX_LEVEL_SYSOP);
+
+ /* session_begin */
+ memset(&sess, 0, sizeof(sess));
+ check_rc("session_begin",
+ hybbx_storage_session_begin(st, &user, "test", &sess), HYBBX_OK);
+ check_nonzero("session id", sess.session_id);
+
+ /* session_end */
+ check_rc("session_end",
+ hybbx_storage_session_end(st, sess.session_id), HYBBX_OK);
+
+ /* delete_user */
+ check_rc("delete_user",
+ hybbx_storage_delete_user(st, user.id), HYBBX_OK);
+
+ /* find after delete */
+ check_rc("find after delete",
+ hybbx_storage_find_user(st, test_user, &found),
+ HYBBX_ERR_NOT_FOUND);
+
+ /* Persistence: close and reopen, verify functional */
+ hybbx_storage_close(st);
+ st = open_backend(backend, path);
+ if (st == NULL) {
+ fprintf(stderr, "FAIL %s: reopen returned NULL\n", label);
+ g_failures++;
+ return;
+ }
+
+ /* Re-register after reopen to verify backend is functional */
+ check_rc("re-register after reopen",
+ hybbx_storage_register_user(st, &reg, &user), HYBBX_OK);
+ check_nonzero("re-registered id", user.id);
+
+ hybbx_storage_delete_user(st, user.id);
+ hybbx_storage_close(st);
+
+ rm_rf(path);
+}
+
+int main(void)
+{
+ char path_ff[256];
+ char path_sql[256];
+
+ snprintf(path_ff, sizeof(path_ff), "/tmp/hybbx-smoke-flatfile-%d",
+ (int)getpid());
+ snprintf(path_sql, sizeof(path_sql), "/tmp/hybbx-smoke-sqlite-%d",
+ (int)getpid());
+
+ smoke_backend(HYBBX_STORAGE_FLATFILE, "flatfile", path_ff);
+ smoke_backend(HYBBX_STORAGE_SQLITE, "sqlite", path_sql);
+
+ if (g_failures != 0) {
+ fprintf(stderr, "%u failure(s)\n", g_failures);
+ return 1;
+ }
+
+ puts("test_storage_smoke: ok");
+ return 0;
+}
git clone -b <branch> https://cgit.mode42.com/<repo>.git
git clone -b <branch> git://cgit.mode42.com/<repo>.git

info@mode42.com