# primitives for emitting traces to a 'trace' stream, and for tests to make assertions on its contents # # A trace stream looks like a regular stream: # write : int # index at which writes go # read : int # index that we've read until # data : (array byte) # prefixed by length as usual # In a real trace the data will be in a special segment set aside for the purpose. # # primitives for operating on traces: # - initialize-trace-stream (update global variable) # - trace: stream, string # - die: stream (exit(1) if using real trace) # - check-trace-contains: stream, string/line, string/message (scans only from stream's read pointer, prints message to stderr on failure, updates stream's read pointer) # - scan-to-next-line: stream (advance read pointer past next newline) # # Traces are very fundamental, so many of the helpers we create here won't be # used elsewhere; we'll switch to more bounds-checked variants. But here we get # bounds-checking for free; we allocate a completely disjoint segment for trace # data, and overflowing it will generate a page fault. == data # We'll save the address of the trace segment here. Trace-stream: 0/imm32 # Fake trace-stream for tests. # Also illustrates the layout of the real trace-stream (segment). _test-trace-stream: # current write index 0/imm32 # current read index 0/imm32 # length 8/imm32 # data 00 00 00 00 00 00 00 00 # 8 bytes == code # instruction effective address register displacement immediate # . op subop mod rm32 base index scale r32 # . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes # Allocate a new segment for the trace stream, initialize its length, and save its address to Trace-stream. # The Trace-stream segment will consist of variable-length lines separated by newlines (0x0a) initialize-trace-stream: # EAX = new-segment(0x1000) # . . push args 68/push 0x1000/imm32/N # . . call e8/call new-segment/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP # copy EAX to *Trace-stream 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy EAX to *Trace-stream # Trace-stream->length = 0x1000/N - 12 c7 0/subop/copy 1/mod/*+disp8 0/rm32/EAX . . . . 8/disp8 0xff4/imm32 # copy 0xff4 to *(EAX+8) c3/return # Append a string to the given trace stream. # Silently give up if it's already full. Or truncate the string if there isn't enough room. trace: # t : (address trace-stream), line : string # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # . save registers 50/push-EAX 51/push-ECX 52/push-EDX 53/push-EBX 56/push-ESI 57/push-EDI # EDI = t 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 7/r32/EDI 8/disp8 . # copy *(EBP+8) to EDI # ESI = line 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI # ECX = t->write 8b/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy *EDI to ECX # EDX = t->length 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 2/r32/EDX 8/disp8 . # copy *(EDI+8) to EDX # EAX = _append-3(&t->data[t->write], &t->data[t->length], line) # . . push line 56/push-ESI # . . push &t->data[t->length] 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 2/index/EDX . 3/r32/EBX 0xc/disp8 . # copy EDI+EDX+12 to EBX 53/push-EBX # . . push &t->data[t->write] 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 1/index/ECX . 3/r32/EBX 0xc/disp8 . # copy EDI+ECX+12 to EBX 53/push-EBX # . . call e8/call _append-3/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP # if (EAX == 0) return 3d/compare-EAX-and 0/imm32 74/jump-if-equal $trace:end/disp8 # t->write += EAX 01/add 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # add EAX to *EDI # refresh ECX = t->write 8b/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy *EDI to ECX # EAX = _append-3(&t->data[t->write], &t->data[t->length], line) # . . push line 68/push Newline/imm32 # . . push &t->data[t->length] 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 2/index/EDX . 3/r32/EBX 0xc/disp8 . # copy EDI+EDX+12 to EBX 53/push-EBX # . . push &t->data[t->write] 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 1/index/ECX . 3/r32/EBX 0xc/disp8 . # copy EDI+ECX+12 to EBX 53/push-EBX # . . call e8/call _append-3/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP # t->write += EAX 01/add 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # add EAX to *EDI $trace:end: # . restore registers 5f/pop-to-EDI 5e/pop-to-ESI 5b/pop-to-EBX 5a/p
package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"
)

// Currently, these only test for a 200 status code.
// More in-depth unit tests are planned, however, several
// of these will quickly turn into integration tests as
// they'll need more than a barebones test environment to
// get any real information. The HTTP responses are being
// tested by me by hand, mostly.
func Test_indexHandler(t *testing.T) {
	initTestConf()
	t.Run("indexHandler", func(t *testing.T) {
		w := httptest.NewRecorder()
		req := httptest.NewRequest("GET", "localhost"+testport+"/", nil)
		indexHandler(w, req)
		resp := w.Result()
		if resp.StatusCode != http.StatusOK {
			t.Errorf(fmt.Sprintf("%v", resp.StatusCode))
		}
	})
}
func Test_apiBaseHandler(t *testing.T) {
	initTestConf()
	t.Run("apiBaseHandler", func(t *testing.T) {
		w := httptest.NewRecorder()
		req := httptest.NewRequest("GET", "localhost"+testport+"/api", nil)
		apiBaseHandler(w, req)
		resp := w.Result()
		if resp.StatusCode != http.StatusOK {
			t.Errorf(fmt.Sprintf("%v", resp.StatusCode))
		}