naett.c

Tiny cross-platform HTTP / HTTPS client library in C.
git clone git://git.finwo.net/lib/naett.c
Log | Files | Refs | README | LICENSE

commit c36fd5b0500e9bbb15b80c2047a96db8376c1bb3
parent 77b391393383b8489c52742a78bbbbcba38d0cc6
Author: Erik Agsjö <erik.agsjo@gmail.com>
Date:   Mon,  6 Dec 2021 22:56:26 +0100

Test rig

Diffstat:
Atestrig/Makefile | 16++++++++++++++++
Atestrig/go.mod | 3+++
Atestrig/rig.go | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atestrig/test.c | 136+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 290 insertions(+), 0 deletions(-)

diff --git a/testrig/Makefile b/testrig/Makefile @@ -0,0 +1,16 @@ +CFLAGS = -I.. -g -Wall -pedantic + +ifeq ($(OS),Windows_NT) + LDFLAGS = -lwinhttp +else + UNAME_S := $(shell uname -s) + ifeq ($(UNAME_S),Darwin) + LDFLAGS = -framework Cocoa + CFLAGS += -Wno-gnu-zero-variadic-macro-arguments + else ifeq ($(UNAME_S),Linux) + LDFLAGS = -lcurl -lpthread + endif +endif + +test: test.c ../naett.c + gcc $^ -o $@ $(CFLAGS) $(LDFLAGS) diff --git a/testrig/go.mod b/testrig/go.mod @@ -0,0 +1,3 @@ +module testrig + +go 1.17 diff --git a/testrig/rig.go b/testrig/rig.go @@ -0,0 +1,135 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + "os/exec" + "path" +) + +func main() { + err := build() + if err != nil { + os.Exit(1) + } + + go serve() + + err = runTest() + if err != nil { + log.Fatal(err) + } +} + +func build() error { + cmd := exec.Command("make") + return cmd.Run() +} + +func runTest() error { + cwd, err := os.Getwd() + if err != nil { + return err + } + cmd := exec.Command(path.Join(cwd, "test"), "http://localhost:4711") + output, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("Failed to run test: %s", string(output)) + } + fmt.Print(string(output)) + return nil +} + +func serve() { + http.HandleFunc("/get", testGETHandler) + http.HandleFunc("/post", testPOSTHandler) + http.HandleFunc("/redirect", testRedirectHandler) + http.HandleFunc("/redirected", redirectedHandler) + log.Fatal(http.ListenAndServe(":4711", nil)) +} + +func fail(w http.ResponseWriter, message string) { + w.WriteHeader(400) + w.Write([]byte(message + "\n")) +} + +func ok(w http.ResponseWriter) { + w.Write([]byte("OK")) +} + +func checkHeader(w http.ResponseWriter, r *http.Request, header string, expected string) bool { + actual := r.Header[header] + if len(actual) == 0 || actual[0] != expected { + fail(w, fmt.Sprintf("Expected header %q to be %q, got %q", header, expected, actual)) + return false + } + return true +} + +func testGETHandler(w http.ResponseWriter, r *http.Request) { + if r.Method != "GET" { + fail(w, fmt.Sprintf("Unexpected method, %q", r.Method)) + return + } + + if r.ContentLength != 0 { + fail(w, "Non-empty body in GET") + return + } + + if !checkHeader(w, r, "Accept", "naett/testresult") { + return + } + + if !checkHeader(w, r, "User-Agent", "Naett/1.0") { + return + } + + ok(w) +} + +func testPOSTHandler(w http.ResponseWriter, r *http.Request) { + if r.Method != "POST" { + fail(w, fmt.Sprintf("Unexpected method, %q", r.Method)) + return + } + + if r.ContentLength == 0 { + fail(w, "Empty body in POST") + return + } + + if !checkHeader(w, r, "Accept", "naett/testresult") { + return + } + + if !checkHeader(w, r, "User-Agent", "Naett/1.0") { + return + } + + bodyBytes, err := ioutil.ReadAll(r.Body) + if err != nil { + fail(w, err.Error()) + } + + body := string(bodyBytes) + expectedBody := "TestRequest!" + + if body != expectedBody { + fail(w, "Unexpected body") + } + + ok(w) +} + +func testRedirectHandler(w http.ResponseWriter, _ *http.Request) { + w.Header().Add("Location", "/redirected") + w.WriteHeader(302) +} + +func redirectedHandler(w http.ResponseWriter, _ *http.Request) { + w.Write([]byte("Redirected")) +} diff --git a/testrig/test.c b/testrig/test.c @@ -0,0 +1,136 @@ +#include "../naett.h" +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> + + +void fail(const char* test, const char* message) { + printf("%s: FAIL - %s\n", test, message); + exit(1); +} + +void verifyBody(naettRes* res, const char* expected) { + int bodyLength = 0; + const char* body = naettGetBody(res, &bodyLength); + + if (body != NULL && strncmp(body, expected, bodyLength) != 0) { + printf("Expected body: [\n%s\n], got: [\n%s]\n", expected, body); + exit(1); + } + + const char* lengthString = naettGetHeader(res, "Content-Length"); + if (lengthString == NULL) { + fail(__func__, "Expected 'Content-Length' header"); + } + const int expectedLength = atoi(lengthString); + if (bodyLength != expectedLength) { + printf("Received body (%d) and 'Content-Length' (%d) mismatch.", bodyLength, expectedLength); + exit(1); + } +} + +void runGETTest(const char* endpoint) { + char testURL[512]; + snprintf(testURL, sizeof(testURL), "%s/get", endpoint); + + naettReq* req = naettRequest(testURL, naettMethod("GET"), naettHeader("accept", "naett/testresult")); + if (req == NULL) { + fail(__func__, "Failed to create request"); + } + + naettRes* res = naettMake(req); + if (req == NULL) { + fail(__func__, "Failed to make request"); + } + + while (!naettComplete(res)) { + usleep(100 * 1000); + } + + if (naettGetStatus(res) < 0) { + fail(__func__, "Connection failed"); + } + + verifyBody(res, "OK"); + + if (naettGetStatus(res) != 200) { + fail(__func__, "Expected 200"); + } +} + +void runPOSTTest(const char* endpoint) { + char testURL[512]; + snprintf(testURL, sizeof(testURL), "%s/post", endpoint); + + naettReq* req = naettRequest(testURL, naettMethod("POST"), naettHeader("accept", "naett/testresult"), naettBody("TestRequest!", 12)); + if (req == NULL) { + fail(__func__, "Failed to create request"); + } + + naettRes* res = naettMake(req); + if (req == NULL) { + fail(__func__, "Failed to make request"); + } + + while (!naettComplete(res)) { + usleep(100 * 1000); + } + + if (naettGetStatus(res) < 0) { + fail(__func__, "Connection failed"); + } + + verifyBody(res, "OK"); + + if (naettGetStatus(res) != 200) { + fail(__func__, "Expected 200"); + } +} + +void runRedirectTest(const char* endpoint) { + char testURL[512]; + snprintf(testURL, sizeof(testURL), "%s/redirect", endpoint); + + naettReq* req = naettRequest(testURL, naettMethod("GET")); + if (req == NULL) { + fail(__func__, "Failed to create request"); + } + + naettRes* res = naettMake(req); + if (req == NULL) { + fail(__func__, "Failed to make request"); + } + + while (!naettComplete(res)) { + usleep(100 * 1000); + } + + if (naettGetStatus(res) < 0) { + fail(__func__, "Connection failed"); + } + + verifyBody(res, "Redirected"); + + if (naettGetStatus(res) != 200) { + fail(__func__, "Expected 200"); + } +} + +void runTests(const char* endpoint) { + naettInit(NULL); + runGETTest(endpoint); + runPOSTTest(endpoint); + runRedirectTest(endpoint); +} + +int main(int argc, char** argv) { + if (argc != 2) { + printf("Expected test endpoint argument\n"); + return 1; + } + const char* endpoint = argv[1]; + runTests(endpoint); + printf("All tests pass OK\n"); + return 0; +}