commit c36fd5b0500e9bbb15b80c2047a96db8376c1bb3
parent 77b391393383b8489c52742a78bbbbcba38d0cc6
Author: Erik Agsjö <erik.agsjo@gmail.com>
Date: Mon, 6 Dec 2021 22:56:26 +0100
Test rig
Diffstat:
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;
+}