chore: add CMake test infrastructure and placeholder unit test files for future coverage

This commit is contained in:
2025-11-28 05:41:42 +00:00
parent 4afdcf567b
commit 53a6179ede
38 changed files with 5192 additions and 21 deletions
@@ -0,0 +1,154 @@
// retoor <retoor@molodetz.nl>
#include "../../test_framework.h"
#include "../http_endpoints.h"
TEST_SUITE(auth_401_challenge)
TEST(no_auth_header_returns_401) {
endpoint_test_ctx_t *ctx = endpoint_test_create();
ASSERT_NOT_NULL(ctx);
storage_write_file(ctx->fixture->storage, "/protected.txt", "secret", 6);
endpoint_test_execute(ctx, "GET", "/protected.txt", NULL, 0);
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
endpoint_test_destroy(ctx);
}
TEST(401_includes_www_authenticate_header) {
endpoint_test_ctx_t *ctx = endpoint_test_create();
ASSERT_NOT_NULL(ctx);
storage_write_file(ctx->fixture->storage, "/protected.txt", "secret", 6);
endpoint_test_execute(ctx, "GET", "/protected.txt", NULL, 0);
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
ASSERT_TRUE(endpoint_response_has_header(ctx, "WWW-Authenticate", NULL));
endpoint_test_destroy(ctx);
}
TEST(401_challenge_includes_realm) {
endpoint_test_ctx_t *ctx = endpoint_test_create();
ASSERT_NOT_NULL(ctx);
storage_write_file(ctx->fixture->storage, "/file.txt", "x", 1);
endpoint_test_execute(ctx, "GET", "/file.txt", NULL, 0);
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
const char *www_auth = endpoint_response_get_header(ctx, "WWW-Authenticate");
ASSERT_NOT_NULL(www_auth);
ASSERT_TRUE(strstr(www_auth, "realm=") != NULL);
endpoint_test_destroy(ctx);
}
TEST(401_for_put_without_auth) {
endpoint_test_ctx_t *ctx = endpoint_test_create();
ASSERT_NOT_NULL(ctx);
endpoint_test_execute(ctx, "PUT", "/newfile.txt", "content", 7);
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
endpoint_test_destroy(ctx);
}
TEST(401_for_delete_without_auth) {
endpoint_test_ctx_t *ctx = endpoint_test_create();
ASSERT_NOT_NULL(ctx);
storage_write_file(ctx->fixture->storage, "/file.txt", "x", 1);
endpoint_test_execute(ctx, "DELETE", "/file.txt", NULL, 0);
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
endpoint_test_destroy(ctx);
}
TEST(401_for_mkcol_without_auth) {
endpoint_test_ctx_t *ctx = endpoint_test_create();
ASSERT_NOT_NULL(ctx);
endpoint_test_execute(ctx, "MKCOL", "/newfolder", NULL, 0);
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
endpoint_test_destroy(ctx);
}
TEST(401_for_proppatch_without_auth) {
endpoint_test_ctx_t *ctx = endpoint_test_create();
ASSERT_NOT_NULL(ctx);
storage_write_file(ctx->fixture->storage, "/file.txt", "x", 1);
const char *body =
"<?xml version=\"1.0\"?>"
"<propertyupdate xmlns=\"DAV:\">"
"<set><prop><displayname>x</displayname></prop></set>"
"</propertyupdate>";
endpoint_test_execute(ctx, "PROPPATCH", "/file.txt", body, strlen(body));
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
endpoint_test_destroy(ctx);
}
TEST(malformed_auth_header_returns_401) {
endpoint_test_ctx_t *ctx = endpoint_test_create();
ASSERT_NOT_NULL(ctx);
storage_write_file(ctx->fixture->storage, "/file.txt", "x", 1);
http_request_init(&ctx->request);
strncpy(ctx->request.method, "GET", sizeof(ctx->request.method) - 1);
strncpy(ctx->request.uri, "/file.txt", sizeof(ctx->request.uri) - 1);
http_request_add_header(&ctx->request, "Authorization", "InvalidScheme xyz123");
http_response_init(&ctx->response);
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
ctx->fixture->props, &ctx->request, &ctx->response);
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
endpoint_test_destroy(ctx);
}
TEST(empty_auth_header_returns_401) {
endpoint_test_ctx_t *ctx = endpoint_test_create();
ASSERT_NOT_NULL(ctx);
storage_write_file(ctx->fixture->storage, "/file.txt", "x", 1);
http_request_init(&ctx->request);
strncpy(ctx->request.method, "GET", sizeof(ctx->request.method) - 1);
strncpy(ctx->request.uri, "/file.txt", sizeof(ctx->request.uri) - 1);
http_request_add_header(&ctx->request, "Authorization", "");
http_response_init(&ctx->response);
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
ctx->fixture->props, &ctx->request, &ctx->response);
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
endpoint_test_destroy(ctx);
}
TEST(options_allowed_without_auth) {
endpoint_test_ctx_t *ctx = endpoint_test_create();
ASSERT_NOT_NULL(ctx);
endpoint_test_execute(ctx, "OPTIONS", "/", NULL, 0);
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
endpoint_test_destroy(ctx);
}
@@ -0,0 +1,138 @@
// retoor <retoor@molodetz.nl>
#include "../../test_framework.h"
#include "../http_endpoints.h"
TEST_SUITE(auth_basic_flow)
TEST(basic_auth_valid_credentials) {
endpoint_test_ctx_t *ctx = endpoint_test_create();
ASSERT_NOT_NULL(ctx);
user_manager_add(ctx->fixture->user_mgr, "testuser", "testpass",
"test@example.com", 0);
storage_write_file(ctx->fixture->storage, "/protected.txt", "secret", 6);
endpoint_test_execute_with_auth(ctx, "GET", "/protected.txt",
"testuser", "testpass", NULL, 0);
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
endpoint_test_destroy(ctx);
}
TEST(basic_auth_invalid_password) {
endpoint_test_ctx_t *ctx = endpoint_test_create();
ASSERT_NOT_NULL(ctx);
user_manager_add(ctx->fixture->user_mgr, "testuser", "correctpass",
"test@example.com", 0);
storage_write_file(ctx->fixture->storage, "/protected.txt", "secret", 6);
endpoint_test_execute_with_auth(ctx, "GET", "/protected.txt",
"testuser", "wrongpass", NULL, 0);
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
endpoint_test_destroy(ctx);
}
TEST(basic_auth_unknown_user) {
endpoint_test_ctx_t *ctx = endpoint_test_create();
ASSERT_NOT_NULL(ctx);
storage_write_file(ctx->fixture->storage, "/protected.txt", "secret", 6);
endpoint_test_execute_with_auth(ctx, "GET", "/protected.txt",
"unknown", "anypass", NULL, 0);
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
endpoint_test_destroy(ctx);
}
TEST(basic_auth_disabled_user) {
endpoint_test_ctx_t *ctx = endpoint_test_create();
ASSERT_NOT_NULL(ctx);
user_manager_add(ctx->fixture->user_mgr, "disabled", "password",
"disabled@example.com", 0);
user_manager_enable(ctx->fixture->user_mgr, "disabled", 0);
storage_write_file(ctx->fixture->storage, "/protected.txt", "secret", 6);
endpoint_test_execute_with_auth(ctx, "GET", "/protected.txt",
"disabled", "password", NULL, 0);
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
endpoint_test_destroy(ctx);
}
TEST(basic_auth_put_file) {
endpoint_test_ctx_t *ctx = endpoint_test_create();
ASSERT_NOT_NULL(ctx);
user_manager_add(ctx->fixture->user_mgr, "writer", "writepass",
"writer@example.com", 0);
const char *content = "new file content";
endpoint_test_execute_with_auth(ctx, "PUT", "/newfile.txt",
"writer", "writepass",
content, strlen(content));
ASSERT_EQUAL(HTTP_201_CREATED, ctx->response.status);
endpoint_test_destroy(ctx);
}
TEST(basic_auth_mkcol) {
endpoint_test_ctx_t *ctx = endpoint_test_create();
ASSERT_NOT_NULL(ctx);
user_manager_add(ctx->fixture->user_mgr, "creator", "createpass",
"creator@example.com", 0);
endpoint_test_execute_with_auth(ctx, "MKCOL", "/newfolder",
"creator", "createpass", NULL, 0);
ASSERT_EQUAL(HTTP_201_CREATED, ctx->response.status);
endpoint_test_destroy(ctx);
}
TEST(basic_auth_delete) {
endpoint_test_ctx_t *ctx = endpoint_test_create();
ASSERT_NOT_NULL(ctx);
user_manager_add(ctx->fixture->user_mgr, "deleter", "deletepass",
"deleter@example.com", 0);
storage_write_file(ctx->fixture->storage, "/todelete.txt", "x", 1);
endpoint_test_execute_with_auth(ctx, "DELETE", "/todelete.txt",
"deleter", "deletepass", NULL, 0);
ASSERT_EQUAL(HTTP_204_NO_CONTENT, ctx->response.status);
endpoint_test_destroy(ctx);
}
TEST(basic_auth_special_chars_in_password) {
endpoint_test_ctx_t *ctx = endpoint_test_create();
ASSERT_NOT_NULL(ctx);
user_manager_add(ctx->fixture->user_mgr, "special", "p@ss:w0rd!#$",
"special@example.com", 0);
storage_write_file(ctx->fixture->storage, "/file.txt", "x", 1);
endpoint_test_execute_with_auth(ctx, "GET", "/file.txt",
"special", "p@ss:w0rd!#$", NULL, 0);
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
endpoint_test_destroy(ctx);
}
@@ -0,0 +1,169 @@
// retoor <retoor@molodetz.nl>
#include "../../test_framework.h"
#include "../http_endpoints.h"
#include "../../src/auth/auth.h"
TEST_SUITE(auth_digest_flow)
static void compute_digest_response(const char *username, const char *password,
const char *realm, const char *nonce,
const char *method, const char *uri,
const char *nc, const char *cnonce,
const char *qop, char *out_response) {
char ha1[65], ha2[65];
char a1[512];
snprintf(a1, sizeof(a1), "%s:%s:%s", username, realm, password);
auth_md5_hex(a1, strlen(a1), ha1);
char a2[512];
snprintf(a2, sizeof(a2), "%s:%s", method, uri);
auth_md5_hex(a2, strlen(a2), ha2);
char response_str[1024];
snprintf(response_str, sizeof(response_str), "%s:%s:%s:%s:%s:%s",
ha1, nonce, nc, cnonce, qop, ha2);
auth_md5_hex(response_str, strlen(response_str), out_response);
}
TEST(digest_auth_valid_credentials) {
endpoint_test_ctx_t *ctx = endpoint_test_create();
ASSERT_NOT_NULL(ctx);
user_manager_add(ctx->fixture->user_mgr, "digestuser", "digestpass",
"digest@example.com", 0);
storage_write_file(ctx->fixture->storage, "/secure.txt", "secret data", 11);
const char *realm = "WebDAV";
const char *nonce = "abc123nonce";
const char *uri = "/secure.txt";
const char *nc = "00000001";
const char *cnonce = "xyz789cnonce";
const char *qop = "auth";
char response[65];
compute_digest_response("digestuser", "digestpass", realm, nonce,
"GET", uri, nc, cnonce, qop, response);
char auth_header[1024];
snprintf(auth_header, sizeof(auth_header),
"Digest username=\"digestuser\", realm=\"%s\", nonce=\"%s\", "
"uri=\"%s\", nc=%s, cnonce=\"%s\", qop=%s, response=\"%s\"",
realm, nonce, uri, nc, cnonce, qop, response);
http_request_init(&ctx->request);
strncpy(ctx->request.method, "GET", sizeof(ctx->request.method) - 1);
strncpy(ctx->request.uri, uri, sizeof(ctx->request.uri) - 1);
http_request_add_header(&ctx->request, "Authorization", auth_header);
http_response_init(&ctx->response);
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
ctx->fixture->props, &ctx->request, &ctx->response);
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
endpoint_test_destroy(ctx);
}
TEST(digest_auth_invalid_response) {
endpoint_test_ctx_t *ctx = endpoint_test_create();
ASSERT_NOT_NULL(ctx);
user_manager_add(ctx->fixture->user_mgr, "testuser", "testpass",
"test@example.com", 0);
storage_write_file(ctx->fixture->storage, "/file.txt", "data", 4);
char auth_header[1024];
snprintf(auth_header, sizeof(auth_header),
"Digest username=\"testuser\", realm=\"WebDAV\", nonce=\"abc123\", "
"uri=\"/file.txt\", nc=00000001, cnonce=\"xyz789\", qop=auth, "
"response=\"invalidresponse\"");
http_request_init(&ctx->request);
strncpy(ctx->request.method, "GET", sizeof(ctx->request.method) - 1);
strncpy(ctx->request.uri, "/file.txt", sizeof(ctx->request.uri) - 1);
http_request_add_header(&ctx->request, "Authorization", auth_header);
http_response_init(&ctx->response);
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
ctx->fixture->props, &ctx->request, &ctx->response);
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
endpoint_test_destroy(ctx);
}
TEST(digest_auth_unknown_user) {
endpoint_test_ctx_t *ctx = endpoint_test_create();
ASSERT_NOT_NULL(ctx);
storage_write_file(ctx->fixture->storage, "/file.txt", "data", 4);
char response[65];
compute_digest_response("unknown", "anypass", "WebDAV", "nonce123",
"GET", "/file.txt", "00000001", "cnonce", "auth", response);
char auth_header[1024];
snprintf(auth_header, sizeof(auth_header),
"Digest username=\"unknown\", realm=\"WebDAV\", nonce=\"nonce123\", "
"uri=\"/file.txt\", nc=00000001, cnonce=\"cnonce\", qop=auth, "
"response=\"%s\"", response);
http_request_init(&ctx->request);
strncpy(ctx->request.method, "GET", sizeof(ctx->request.method) - 1);
strncpy(ctx->request.uri, "/file.txt", sizeof(ctx->request.uri) - 1);
http_request_add_header(&ctx->request, "Authorization", auth_header);
http_response_init(&ctx->response);
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
ctx->fixture->props, &ctx->request, &ctx->response);
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
endpoint_test_destroy(ctx);
}
TEST(digest_auth_put_operation) {
endpoint_test_ctx_t *ctx = endpoint_test_create();
ASSERT_NOT_NULL(ctx);
user_manager_add(ctx->fixture->user_mgr, "writer", "writepass",
"writer@example.com", 0);
const char *realm = "WebDAV";
const char *nonce = "putnonce";
const char *uri = "/newfile.txt";
const char *nc = "00000001";
const char *cnonce = "putcnonce";
const char *qop = "auth";
char response[65];
compute_digest_response("writer", "writepass", realm, nonce,
"PUT", uri, nc, cnonce, qop, response);
char auth_header[1024];
snprintf(auth_header, sizeof(auth_header),
"Digest username=\"writer\", realm=\"%s\", nonce=\"%s\", "
"uri=\"%s\", nc=%s, cnonce=\"%s\", qop=%s, response=\"%s\"",
realm, nonce, uri, nc, cnonce, qop, response);
const char *content = "file content";
http_request_init(&ctx->request);
strncpy(ctx->request.method, "PUT", sizeof(ctx->request.method) - 1);
strncpy(ctx->request.uri, uri, sizeof(ctx->request.uri) - 1);
http_request_add_header(&ctx->request, "Authorization", auth_header);
ctx->request.body = strdup(content);
ctx->request.body_len = strlen(content);
ctx->request.content_length = strlen(content);
http_response_init(&ctx->response);
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
ctx->fixture->props, &ctx->request, &ctx->response);
ASSERT_EQUAL(HTTP_201_CREATED, ctx->response.status);
endpoint_test_destroy(ctx);
}