Files
zftpd/tests/test_http_system.c
seregonwar 15114b8af1 test(http): cover archive extraction and the system endpoints
Extend the HTTP suite with the archive extraction fixtures (good, traversal
and symlink cases) and the system endpoints, so the split APIs keep their
behavior pinned.
2026-09-30 17:51:39 +02:00

112 lines
3.4 KiB
C

#include "http_api.h"
#include "../src/http/http_api_internal.h"
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#define CHECK(x) do { if (!(x)) { \
fprintf(stderr, "FAIL %s:%d: %s\n", __FILE__, __LINE__, #x); \
return 1; \
} } while (0)
static int response_is(http_response_t *resp, int code) {
if (resp == NULL || resp->used == 0U) return 0;
char expected[32];
(void)snprintf(expected, sizeof(expected), "HTTP/1.1 %d", code);
return strncmp(resp->data, expected, strlen(expected)) == 0;
}
static http_response_t *request(http_method_t method, const char *uri) {
http_request_t req;
memset(&req, 0, sizeof(req));
req.method = method;
(void)snprintf(req.uri, sizeof(req.uri), "%s", uri);
return http_api_system_handle(&req);
}
int main(void) {
char root[] = "/tmp/zftpd-http-system-XXXXXX";
CHECK(mkdtemp(root) != NULL);
http_api_set_root(root);
char file[1024];
(void)snprintf(file, sizeof(file), "%s/item.txt", root);
FILE *f = fopen(file, "wb");
CHECK(f != NULL);
CHECK(fwrite("data", 1U, 4U, f) == 4U);
fclose(f);
http_response_t *resp = request(HTTP_METHOD_GET, "/api/status");
CHECK(response_is(resp, 200));
http_response_destroy(resp);
resp = request(HTTP_METHOD_GET, "/api/stats/ram");
CHECK(response_is(resp, 200));
http_response_destroy(resp);
resp = request(HTTP_METHOD_GET, "/api/stats/system");
CHECK(response_is(resp, 200));
http_response_destroy(resp);
char uri[2048];
(void)snprintf(uri, sizeof(uri), "/api/stats?path=%s", root);
resp = request(HTTP_METHOD_GET, uri);
CHECK(response_is(resp, 200));
http_response_destroy(resp);
resp = request(HTTP_METHOD_GET, "/api/disk/info");
CHECK(response_is(resp, 200));
http_response_destroy(resp);
(void)snprintf(uri, sizeof(uri), "/api/disk/tree?path=%s", root);
resp = request(HTTP_METHOD_GET, uri);
CHECK(response_is(resp, 200));
http_response_destroy(resp);
resp = request(HTTP_METHOD_GET, "/api/status-extra");
CHECK(resp == NULL);
resp = request(HTTP_METHOD_GET, "/api/network/reset");
CHECK(response_is(resp, 405));
http_response_destroy(resp);
/* Mounts: the host has no /mnt/usbN, and a plain directory must never be
* reported as a volume. */
resp = request(HTTP_METHOD_GET, "/api/mounts");
CHECK(response_is(resp, 200));
CHECK(strstr(resp->data, "\"mounts\":[]") != NULL);
http_response_destroy(resp);
/* Blu-ray drive: the host build has no device node, so the state reports
* no drive and the eject answers a soft failure naming the real reason. */
resp = request(HTTP_METHOD_GET, "/api/system/disc");
CHECK(response_is(resp, 200));
CHECK(strstr(resp->data, "\"present\":false") != NULL);
http_response_destroy(resp);
resp = request(HTTP_METHOD_POST, "/api/system/eject");
CHECK(response_is(resp, 200));
CHECK(strstr(resp->data, "\"ok\":false") != NULL);
CHECK(strstr(resp->data, "not available") != NULL);
http_response_destroy(resp);
resp = request(HTTP_METHOD_GET, "/api/system/eject");
CHECK(response_is(resp, 405));
http_response_destroy(resp);
resp = request(HTTP_METHOD_POST, "/api/system/disc");
CHECK(response_is(resp, 405));
http_response_destroy(resp);
resp = request(HTTP_METHOD_GET, "/api/notify");
CHECK(response_is(resp, 400));
http_response_destroy(resp);
CHECK(unlink(file) == 0);
CHECK(rmdir(root) == 0);
http_api_set_root("/");
puts("test_http_system: ok");
return 0;
}