commit eaecb958183f6eb4fdb79b3258d465a4fd8cb72e from: Mark Jamsek via: Thomas Adam date: Sun Nov 24 13:41:55 2024 UTC implement gotwebd test harness Only a couple basic regress tests so far for the index/summary and diff pages. Documentation is still needed. ok stsp@ commit - 52ba27b372c79f398a374541cae9f306284131c7 commit + eaecb958183f6eb4fdb79b3258d465a4fd8cb72e blob - /dev/null blob + 91d341dc319c3e0475087f52ae0c6e121584398a (mode 644) --- /dev/null +++ regress/gotwebd/Makefile @@ -0,0 +1,90 @@ +.PATH:${.CURDIR}/../../lib + +REGRESS_TARGETS=test_gotwebd + +PROG = gotwebd_test +SRCS = gotwebd_test.c error.c hash.c pollfd.c + +CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib + +NOMAN = yes + +NOOBJ=Yes + +.PHONY: ensure_root prepare_test_env prepare_test_repo start_gotwebd + +GOTWEBD_TEST_TMPDIR=/tmp +GOTWEBD_TEST_ROOT?!!=mktemp -d "${GOTWEBD_TEST_TMPDIR}/gotwebd-test-XXXXXXXXXX" +GOTWEBD_TEST_CHROOT=${GOTWEBD_TEST_ROOT}/var/www +GOTWEBD_TEST_CONF=${GOTWEBD_TEST_ROOT}/gotwebd.conf +GOTWEBD_TEST_SOCK=${GOTWEBD_TEST_CHROOT}/gotweb.sock +GOTWEBD_TEST_FCGI=${.OBJDIR}/${PROG} + +GOTWEBD_TEST_USER?=${DOAS_USER} +.if empty(GOTWEBD_TEST_USER) +GOTWEBD_TEST_USER=${SUDO_USER} +.endif +.if empty(GOTWEBD_TEST_USER) +GOTWEBD_TEST_USER=${USER} +.endif + +GOTWEBD_TEST_USER_HOME!=getent passwd ${GOTWEBD_TEST_USER} | cut -d: -f6 + +PREFIX ?= /usr/local +BINDIR ?= ${PREFIX}/sbin + +GOTWEBD_START_CMD?=${BINDIR}/gotwebd -vvf ${GOTWEBD_TEST_CONF} +GOTWEBD_STOP_CMD?=pkill -TERM -fx '${GOTWEBD_START_CMD}' +GOTWEBD_TRAP=trap "${GOTWEBD_STOP_CMD}" HUP INT QUIT PIPE TERM + +GOTWEBD_TEST_ENV=GOTWEBD_TEST_SOCK=${GOTWEBD_TEST_SOCK} \ + GOTWEBD_TEST_CHROOT=${GOTWEBD_TEST_CHROOT} \ + GOTWEBD_TEST_ROOT=${GOTWEBD_TEST_ROOT} \ + GOTWEBD_TEST_CONF=${GOTWEBD_TEST_CONF} \ + GOTWEBD_TEST_USER=${GOTWEBD_TEST_USER} \ + GOTWEBD_TEST_FCGI=${GOTWEBD_TEST_FCGI} \ + GOTWEBD_TEST_FCGI=${GOTWEBD_TEST_FCGI} \ + PATH=$(GOTWEBD_TEST_USER_HOME)/bin:${PATH} \ + HOME=$(GOTWEBD_TEST_USER_HOME) + +ensure_root: + @if [[ `id -u` -ne 0 ]]; then \ + echo gotwebd test suite must be started by root >&2; \ + false; \ + fi ; \ + if [[ "${GOTWEBD_TEST_USER}" = "root" ]]; then \ + echo GOTWEBD_TEST_USER must be a non-root user >&2; \ + false; \ + fi + +gotwebd_libexec: + @su -m ${GOTWEBD_TEST_USER} -c \ + '${MAKE} -C ${.CURDIR}/../../gotwebd/libexec' >/dev/null 2>&1 + +prepare_test_env: gotwebd_libexec ensure_root + @mkdir -p "${GOTWEBD_TEST_CHROOT}" + @DESTDIR=${GOTWEBD_TEST_ROOT} \ + ${MAKE} -C ${.CURDIR}/../../gotwebd/libexec install >/dev/null 2>&1 + @chown ${GOTWEBD_TEST_USER} "${GOTWEBD_TEST_ROOT}" \ + "${GOTWEBD_TEST_CHROOT}" + +prepare_test_repo: prepare_test_env + @su -m ${GOTWEBD_TEST_USER} -c 'env ${GOTWEBD_TEST_ENV} \ + sh ./prepare_test_repo.sh "${GOTWEBD_TEST_CHROOT}"' + +start_gotwebd: prepare_test_repo gotwebd_test + @echo 'user "${GOTWEBD_TEST_USER}"' > ${GOTWEBD_TEST_CONF} + @echo 'chroot "${GOTWEBD_TEST_CHROOT}"' >> ${GOTWEBD_TEST_CONF} + @echo 'listen on socket "${GOTWEBD_TEST_SOCK}"' >> ${GOTWEBD_TEST_CONF} + @echo 'server "localhost" {' >> ${GOTWEBD_TEST_CONF} + @echo ' show_repo_owner off' >> ${GOTWEBD_TEST_CONF} + @echo '}' >> ${GOTWEBD_TEST_CONF} + @${GOTWEBD_TRAP}; ${GOTWEBD_START_CMD} + @${GOTWEBD_TRAP}; sleep .5 + +test_gotwebd: start_gotwebd + @-$(GOTWEBD_TRAP); su -m ${GOTWEBD_TEST_USER} -c \ + 'env $(GOTWEBD_TEST_ENV) sh ./test_gotwebd.sh' + @${GOTWEBD_STOP_CMD} 2>/dev/null + +.include blob - /dev/null blob + 681cedc2e3bbeb0d09075359cb45e7be7e8a45df (mode 644) --- /dev/null +++ regress/gotwebd/action_commit.html @@ -0,0 +1,32 @@ +Content-Security-Policy: default-src 'self'; script-src 'none'; object-src 'none'; +Content-Type: text/html + +Gotweb

Commit Diff


commit - /dev/null
+commit + ${COMMIT_ID}
+blob - /dev/null
+blob + ${BLOB_ALPHA} (mode 644)
+--- /dev/null
++++ alpha
+@@ -0,0 +1 @@
++alpha
+blob - /dev/null
+blob + ${BLOB_BETA} (mode 644)
+--- /dev/null
++++ beta
+@@ -0,0 +1 @@
++beta
+blob - /dev/null
+blob + ${BLOB_ZETA} (mode 644)
+--- /dev/null
++++ epsilon/zeta
+@@ -0,0 +1 @@
++zeta
+blob - /dev/null
+blob + ${BLOB_DELTA} (mode 644)
+--- /dev/null
++++ gamma/delta
+@@ -0,0 +1 @@
++delta
+

Got Owner

blob - /dev/null blob + b976197617d10a91b220cac19df18a839c0c317b (mode 644) --- /dev/null +++ regress/gotwebd/action_index.html @@ -0,0 +1,5 @@ +Content-Security-Policy: default-src 'self'; script-src 'none'; object-src 'none'; +Content-Type: text/html + +Gotweb

Commit Briefs

${COMMIT_ID10} Flan Hacker

import the test tree (main)


Branches

Tags

This repository contains no tags

Got Owner

blob - /dev/null blob + d7ef5732c24f80f6d83250e1af12fa4f13c315c9 (mode 644) --- /dev/null +++ regress/gotwebd/common.sh @@ -0,0 +1,103 @@ +#!/bin/sh +# +# Copyright (c) 2019, 2020 Stefan Sperling +# Copyright (c) 2024 Mark Jamsek +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +. ../cmdline/common.sh + +interpolate() +{ + perl -p -e \ + 's/\$\{(\w+)\}/(exists $ENV{$1} ? $ENV{$1} : "UNDEFINED $1")/eg' \ + < "$1" +} + +test_cleanup() +{ + local testroot="$1" + local repo="$2" + + if [ -n "$repo" ]; then + git_fsck $testroot $repo + ret=$? + if [ $ret -ne 0 ]; then + return $ret + fi + fi + + rm -rf "$testroot" +} + +test_done() +{ + local testroot="$1" + local repo="$2" + local result="$3" + + if [ "$result" = "0" ]; then + test_cleanup "$testroot" "$repo" || return 1 + if [ -z "$GOT_TEST_QUIET" ]; then + echo "ok" + fi + elif echo "$result" | grep -q "^xfail"; then + # expected test failure; test reproduces an unfixed bug + echo "$result" + test_cleanup "$testroot" "$repo" || return 1 + else + echo "test failed; leaving test data in $testroot" + fi +} + +test_init() +{ + local testname="$1" + local no_repo="$2" + + if [ -z "$testname" ]; then + echo "No test name provided" >&2 + return 1 + fi + + local testroot=$(mktemp -d \ + "$GOTWEBD_TEST_ROOT/gotwebd-test-$testname-XXXXXXXXXX") + + if [ -z "$no_repo" ]; then + mkdir $testroot/repo + git_init $testroot/repo + make_test_tree $testroot/repo + git -C $repo add . + git_commit $testroot/repo -m "adding the test tree" + fi + + echo "$testroot" +} + +run_test() +{ + testfunc="$1" + + if [ -n "$regress_run_only" ]; then + case "$regress_run_only" in + *$testfunc*) ;; + *) return ;; + esac + fi + + if [ -z "$GOT_TEST_QUIET" ]; then + echo -n "$testfunc " + fi + + $testfunc +} blob - /dev/null blob + c860ec205f79a0008dd231920f23f8fb1ba69716 (mode 644) --- /dev/null +++ regress/gotwebd/gotwebd_test.c @@ -0,0 +1,455 @@ +/* + * Copyright (c) 2024 Mark Jamsek + * Copyright (c) 2014 Florian Obser + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "got_error.h" +#include "got_lib_poll.h" + +#ifndef nitems +#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) +#endif + +#define GOTWEBD_TEST_HARNESS "gotwebd_test_harness" + +/* + * Socket path should be passed on the command line or set as an envvar. + * Query string and request method can be passed on the command line; + * if not provided, use the index summary page and GET request method. + */ +#define GOTWEBD_TEST_QUERYSTRING "action=summary&path=repo.git" + +#define GOTWEBD_TEST_PATH_INFO "/"GOTWEBD_TEST_HARNESS"/" +#define GOTWEBD_TEST_REMOTE_ADDR "::1" +#define GOTWEBD_TEST_REMOTE_PORT "32768" +#define GOTWEBD_TEST_SERVER_ADDR "::1" +#define GOTWEBD_TEST_SERVER_PORT "80" +#define GOTWEBD_TEST_SERVER_NAME "gotwebd" +#define GOTWEBD_TEST_SCRIPT_NAME GOTWEBD_TEST_HARNESS +#define GOTWEBD_TEST_REQUEST_URI "/"GOTWEBD_TEST_HARNESS"/" +#define GOTWEBD_TEST_DOCUMENT_URI "/"GOTWEBD_TEST_HARNESS"/" +#define GOTWEBD_TEST_DOCUMENT_ROOT "/cgi-bin/"GOTWEBD_TEST_HARNESS +#define GOTWEBD_TEST_REQUEST_METHOD "GET" +#define GOTWEBD_TEST_SCRIPT_FILENAME "/cgi-bin/"GOTWEBD_TEST_HARNESS +#define GOTWEBD_TEST_SERVER_PROTOCOL "HTTP/1.1" +#define GOTWEBD_TEST_SERVER_SOFTWARE GOTWEBD_TEST_HARNESS +#define GOTWEBD_TEST_GATEWAY_INTERFACE "CGI/1.1" + +#define PARAM(_p) { #_p, GOTWEBD_TEST_##_p } + +static const char *mock_params[][2] = { + PARAM(PATH_INFO), + PARAM(REMOTE_ADDR), + PARAM(REMOTE_PORT), + PARAM(SERVER_ADDR), + PARAM(SERVER_PORT), + PARAM(SERVER_NAME), + PARAM(SCRIPT_NAME), + PARAM(REQUEST_URI), + PARAM(DOCUMENT_URI), + PARAM(DOCUMENT_ROOT), + PARAM(REQUEST_METHOD), + PARAM(SCRIPT_FILENAME), + PARAM(SERVER_PROTOCOL), + PARAM(SERVER_SOFTWARE), + PARAM(GATEWAY_INTERFACE) +}; + +#undef PARAM + +#define FCGI_CONTENT_SIZE 65535 +#define FCGI_PADDING_SIZE 255 +#define FCGI_RECORD_SIZE \ + (sizeof(struct fcgi_record_header) + FCGI_CONTENT_SIZE + FCGI_PADDING_SIZE) + +#define FCGI_BEGIN_REQUEST 1 +#define FCGI_ABORT_REQUEST 2 +#define FCGI_END_REQUEST 3 +#define FCGI_PARAMS 4 +#define FCGI_STDIN 5 +#define FCGI_STDOUT 6 +#define FCGI_STDERR 7 +#define FCGI_DATA 8 +#define FCGI_GET_VALUES 9 +#define FCGI_GET_VALUES_RESULT 10 +#define FCGI_UNKNOWN_TYPE 11 +#define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE) + +#define FCGI_RESPONDER 1 + +struct fcgi_record_header { + uint8_t version; + uint8_t type; + uint16_t id; + uint16_t content_len; + uint8_t padding_len; + uint8_t reserved; +}__attribute__((__packed__)); + +struct fcgi_begin_request_body { + uint16_t role; + uint8_t flags; + uint8_t reserved[5]; +}__attribute__((__packed__)); + +struct server_fcgi_param { + int total_len; + uint8_t buf[FCGI_RECORD_SIZE]; +}; + +enum fcgistate { + FCGI_READ_HEADER, + FCGI_READ_CONTENT, + FCGI_READ_PADDING +}; + +struct fcgi_data { + enum fcgistate state; + int toread; + int padding_len; + int type; + int status; +}; + +__dead static void +usage(void) +{ + fprintf(stderr, "usage: %s [-m method] [-q query] [-s socket]\n", + getprogname()); + exit(1); +} + +static const struct got_error * +fcgi_writechunk(int type, uint8_t *dat, size_t datlen) +{ + if (type == FCGI_END_REQUEST) + datlen = 0; + + if (datlen > 0) { + if (write(STDOUT_FILENO, dat, datlen) == -1) + return got_error_from_errno("write"); + } else if (fputs("\r\n", stdout) == EOF) + return got_error_from_errno("fputs"); + + return NULL; +} + +static const struct got_error * +fcgi_read(int fd, struct fcgi_data *fcgi) +{ + const struct got_error *err; + struct fcgi_record_header *h; + char buf[FCGI_RECORD_SIZE]; + size_t len; + + do { + if (fcgi->toread > sizeof(buf)) { + /* cannot happen with gotwebd response */ + return got_error_msg(GOT_ERR_NO_SPACE, + "bad fcgi response size"); + } + + err = got_poll_read_full(fd, &len, buf, + fcgi->toread, fcgi->toread); + if (err != NULL) { + if (err->code != GOT_ERR_EOF) + return err; + err = NULL; + break; + } + + fcgi->toread -= len; + if (fcgi->toread != 0) + return got_error_msg(GOT_ERR_BAD_PACKET, + "short fcgi response"); + + switch (fcgi->state) { + case FCGI_READ_HEADER: + h = (struct fcgi_record_header *)buf; + fcgi->type = h->type; + fcgi->state = FCGI_READ_CONTENT; + fcgi->padding_len = h->padding_len; + fcgi->toread = ntohs(h->content_len); + + if (fcgi->toread != 0) + break; + + /* fallthrough if content_len == 0 */ + case FCGI_READ_CONTENT: + switch (fcgi->type) { + case FCGI_STDERR: /* gotwebd doesn't send STDERR */ + case FCGI_STDOUT: + case FCGI_END_REQUEST: + err = fcgi_writechunk(fcgi->type, buf, len); + if (err != NULL) + return err; + break; + } + if (fcgi->padding_len == 0) { + fcgi->state = FCGI_READ_HEADER; + fcgi->toread = sizeof(*h); + } else { + fcgi->state = FCGI_READ_PADDING; + fcgi->toread = fcgi->padding_len; + } + break; + case FCGI_READ_PADDING: + fcgi->state = FCGI_READ_HEADER; + fcgi->toread = sizeof(*h); + break; + default: + /* should not happen with gotwebd */ + return got_error_msg(GOT_ERR_RANGE, "bad fcgi state"); + } + } while (len > 0); + + return NULL; +} + +static const struct got_error * +fcgi_add_stdin(int fd) +{ + struct fcgi_record_header h; + + memset(&h, 0, sizeof(h)); + h.version = 1; + h.type = FCGI_STDIN; + h.id = htons(1); + h.padding_len = 0; + h.content_len = 0; + + return got_poll_write_full(fd, &h, sizeof(h)); +} + +static const struct got_error * +fcgi_add_param(int fd, struct server_fcgi_param *p, + const char *key, const char *val) +{ + struct fcgi_record_header *h; + int len, key_len, val_len; + uint8_t *param; + + key_len = strlen(key); + val_len = strlen(val); + len = key_len + val_len; + len += key_len > 127 ? 4 : 1; + len += val_len > 127 ? 4 : 1; + + if (len > FCGI_CONTENT_SIZE) + return got_error_msg(GOT_ERR_RANGE, "parameter too large"); + + if (p->total_len + len > FCGI_CONTENT_SIZE) { + const struct got_error *err; + + err = got_poll_write_full(fd, p->buf, + sizeof(*h) + p->total_len); + if (err != NULL) + return err; + p->total_len = 0; + } + + h = (struct fcgi_record_header *)p->buf; + param = p->buf + sizeof(*h) + p->total_len; + + if (key_len > 127) { + *param++ = ((key_len >> 24) & 0xff) | 0x80; + *param++ = ((key_len >> 16) & 0xff); + *param++ = ((key_len >> 8) & 0xff); + *param++ = (key_len & 0xff); + } else + *param++ = key_len; + + if (val_len > 127) { + *param++ = ((val_len >> 24) & 0xff) | 0x80; + *param++ = ((val_len >> 16) & 0xff); + *param++ = ((val_len >> 8) & 0xff); + *param++ = (val_len & 0xff); + } else + *param++ = val_len; + + memcpy(param, key, key_len); + param += key_len; + memcpy(param, val, val_len); + + p->total_len += len; + + h->content_len = htons(p->total_len); + return NULL; +} + +static const struct got_error * +fcgi_send_params(int fd, struct server_fcgi_param *param, + const char *meth, const char *qs) +{ + const struct got_error *err; + struct fcgi_record_header *h; + const char *k, *v; + int i; + + h = (struct fcgi_record_header *)¶m->buf; + h->type = FCGI_PARAMS; + h->content_len = 0; + + for (i = 0; i < nitems(mock_params); ++i) { + k = mock_params[i][0]; + v = mock_params[i][1]; + if ((err = fcgi_add_param(fd, param, k, v)) != NULL) + return err; + } + if (qs == NULL) + qs = GOTWEBD_TEST_QUERYSTRING; + if ((err = fcgi_add_param(fd, param, "QUERY_STRING", qs)) != NULL) + return err; + if (meth == NULL) + meth = GOTWEBD_TEST_REQUEST_METHOD; + if ((err = fcgi_add_param(fd, param, "REQUEST_METHOD", meth)) != NULL) + return err; + + err = got_poll_write_full(fd, param->buf, + sizeof(*h) + ntohs(h->content_len)); + if (err != NULL) + return err; + + /* send "no more params" message */ + h->content_len = 0; + return got_poll_write_full(fd, param->buf, sizeof(*h)); +} + +static const struct got_error * +fcgi(const char *sock, const char *meth, const char *qs) +{ + const struct got_error *err; + struct server_fcgi_param param; + struct fcgi_record_header *h; + struct fcgi_begin_request_body *begin; + struct fcgi_data fcgi; + struct sockaddr_un sun; + int fd = -1; + + if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1) + return got_error_from_errno("socket"); + + memset(&sun, 0, sizeof(sun)); + sun.sun_family = AF_UNIX; + + if (strlcpy(sun.sun_path, sock, sizeof(sun.sun_path)) + >= sizeof(sun.sun_path)) { + err = got_error_fmt(GOT_ERR_NO_SPACE, + "socket path too long: %s", sock); + goto done; + } + + if ((connect(fd, (struct sockaddr *)&sun, sizeof(sun))) == -1) { + err = got_error_from_errno_fmt("connect: %s", sock); + goto done; + } + + if (pledge("stdio", NULL) == -1) { + err = got_error_from_errno("pledge"); + goto done; + } + + memset(&fcgi, 0, sizeof(fcgi)); + + fcgi.state = FCGI_READ_HEADER; + fcgi.toread = sizeof(*h); + fcgi.status = 200; + + memset(¶m, 0, sizeof(param)); + + h = (struct fcgi_record_header *)¶m.buf; + h->version = 1; + h->type = FCGI_BEGIN_REQUEST; + h->id = htons(1); + h->content_len = htons(sizeof(*begin)); + h->padding_len = 0; + + begin = (struct fcgi_begin_request_body *)¶m.buf[sizeof(*h)]; + begin->role = htons(FCGI_RESPONDER); + + err = got_poll_write_full(fd, param.buf, sizeof(*h) + sizeof(*begin)); + if (err != NULL) + goto done; + + if ((err = fcgi_send_params(fd, ¶m, meth, qs)) != NULL) + goto done; + + if ((err = fcgi_add_stdin(fd)) != NULL) + goto done; + + err = fcgi_read(fd, &fcgi); + + done: + if (fd != -1 && close(fd) == EOF && err == NULL) + err = got_error_from_errno("close"); + return err; +} + +int +main(int argc, char *argv[]) +{ + const struct got_error *error; + const char *meth = NULL, *qs = NULL, *sock = NULL; + int ch; + + while ((ch = getopt(argc, argv, "m:q:s:")) != -1) { + switch (ch) { + case 'm': + meth = optarg; + break; + case 'q': + qs = optarg; + break; + case 's': + sock = optarg; + break; + default: + usage(); + /* NOTREACHED */ + } + } + + argc -= optind; + argv += optind; + + if (argc != 0) + usage(); + + if (sock == NULL) { + sock = getenv("GOTWEBD_TEST_SOCK"); + if (sock == NULL) + errx(1, "socket path not provided"); + } + + if (unveil(sock, "rw") != 0) + err(1, "unveil"); + if (pledge("stdio unix", NULL) == -1) + err(1, "pledge"); + + error = fcgi(sock, meth, qs); + if (error != NULL) + errx(1, "%s", error->msg); + + return 0; +} blob - /dev/null blob + c69f369c8092cbd1911705cfd13c37bb20a570b1 (mode 644) --- /dev/null +++ regress/gotwebd/prepare_test_repo.sh @@ -0,0 +1,55 @@ +#!/bin/sh +# +# Copyright (c) 2024 Mark Jamsek +# Copyright (c) 2022 Stefan Sperling +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +. ./common.sh + +make_repo() +{ + local chroot="$1" + local no_tree="$2" + local repo_path="${chroot}/got/public/repo.git" + + if [ -e "${chroot}/got" ]; then + rm -rf "${chroot}/got" + fi + + mkdir -p "${chroot}/got/public" + if [ $? -ne 0 ]; then + echo "failed to make gotweb public repositories tree" + return 1 + fi + + gotadmin init -A "$GOT_TEST_ALGO" "${repo_path}" + + if [ -n "$no_tree" ]; then + return + fi + + test_tree=$(mktemp -d "${chroot}/gotwebd-test-tree-XXXXXXXXXX") + make_test_tree "$test_tree" + + got import -m "import the test tree" -r "${repo_path}" "$test_tree" \ + > /dev/null + if [ $? -ne 0 ]; then + echo "failed to import test tree" + return 1 + fi + + rm -r "$test_tree" # TODO: trap +} + +make_repo "$@" blob - /dev/null blob + 835f0a599f14f193c79d96780f45c2df410e6988 (mode 644) --- /dev/null +++ regress/gotwebd/test_gotwebd.sh @@ -0,0 +1,78 @@ +#!/bin/sh +# +# Copyright (c) 2024 Mark Jamsek +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +. ./common.sh + +test_gotwebd_action_index() +{ + local testroot=$(test_init gotwebd_action_index 1) + local repo="${GOTWEBD_TEST_CHROOT}/got/public/repo.git" + local author_time=$(git_show_author_time $repo) + local id=$(git_show_head $repo) + + COMMIT_ID=$id \ + COMMIT_ID10=$(printf '%.10s' $id) \ + COMMIT_YMDHMS=$(date -u -r $author_time +"%FT%TZ") \ + interpolate action_index.html > $testroot/content.expected + + $GOTWEBD_TEST_FCGI > $testroot/content + + cmp -s $testroot/content.expected $testroot/content + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/content.expected $testroot/content + test_done "$testroot" "" "$ret" + return 1 + fi + + test_done "$testroot" "" "$ret" +} + +test_gotwebd_action_commit() +{ + local testroot=$(test_init gotwebd_action_commit 1) + local repo="${GOTWEBD_TEST_CHROOT}/got/public/repo.git" + local id=$(git_show_head $repo) + local author_time=$(git_show_author_time $repo) + local qs="action=diff&commit=${id}&headref=HEAD&path=repo.git" + + COMMIT_ID=$id \ + BLOB_ALPHA=$(get_blob_id $repo "" alpha) \ + BLOB_BETA=$(get_blob_id $repo "" beta) \ + BLOB_ZETA=$(get_blob_id $repo epsilon zeta) \ + BLOB_DELTA=$(get_blob_id $repo gamma delta) \ + COMMITTER="Flan Hacker" \ + COMMITTER_EMAIL="flan_hacker@openbsd.org" \ + COMMIT_YMDHMS=$(date -u -r $author_time +"%FT%TZ") \ + COMMIT_DATE=$(date -u -r $author_time +"%a %b %e %X %Y") \ + interpolate action_commit.html > $testroot/content.expected + + $GOTWEBD_TEST_FCGI -q "$qs" > $testroot/content + + cmp -s $testroot/content.expected $testroot/content + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/content.expected $testroot/content + test_done "$testroot" "$repo" "$ret" + return 1 + fi + + test_done "$testroot" "$repo" "$ret" +} + +test_parseargs "$@" +run_test test_gotwebd_action_index +run_test test_gotwebd_action_commit