main_test.go (2271B)
1 package main 2 3 import ( 4 "bytes" 5 "context" 6 "log" 7 "net/http" 8 "net/http/httptest" 9 "os" 10 "strings" 11 "syscall" 12 "testing" 13 "time" 14 ) 15 16 // Test that the logging middleware delegates to the next handler 17 // and emits a log line containing the method and path. 18 func TestLoggingMiddleware_EmitsAndDelegates(t *testing.T) { 19 // Not parallel: modifies global logger output 20 called := false 21 next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 22 called = true 23 w.WriteHeader(http.StatusNoContent) 24 }) 25 26 var buf bytes.Buffer 27 log.SetOutput(&buf) 28 defer log.SetOutput(os.Stderr) 29 30 h := logging(next) 31 32 rr := httptest.NewRecorder() 33 req := httptest.NewRequest(http.MethodGet, "/hello", nil) 34 35 h.ServeHTTP(rr, req) 36 37 if !called { 38 t.Fatalf("expected next handler to be called") 39 } 40 if rr.Code != http.StatusNoContent { 41 t.Fatalf("expected status %d, got %d", http.StatusNoContent, rr.Code) 42 } 43 44 out := buf.String() 45 if !strings.Contains(out, "GET") || !strings.Contains(out, "/hello") { 46 t.Fatalf("expected log to contain method and path, got: %q", out) 47 } 48 } 49 50 // TestMainLifecycle starts main() with ephemeral address and temp DB, 51 // waits for the listening log, then sends SIGTERM to trigger graceful shutdown. 52 func TestMainLifecycle_StartsAndShutsDown(t *testing.T) { 53 // Not parallel: uses Setenv and sends process signals 54 var buf bytes.Buffer 55 log.SetOutput(&buf) 56 defer log.SetOutput(os.Stderr) 57 58 tempDB := t.TempDir() + "/test.db" 59 // Provide flags to main via os.Args. 60 oldArgs := os.Args 61 os.Args = []string{"marky", "--addr", "127.0.0.1:0", "--db", tempDB} 62 defer func() { os.Args = oldArgs }() 63 64 done := make(chan struct{}) 65 go func() { 66 main() 67 close(done) 68 }() 69 70 ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) 71 defer cancel() 72 for { 73 select { 74 case <-ctx.Done(): 75 t.Fatalf("did not observe listening log: %q", buf.String()) 76 default: 77 if strings.Contains(buf.String(), "marky API listening on") { 78 goto running 79 } 80 time.Sleep(10 * time.Millisecond) 81 } 82 } 83 running: 84 if err := syscall.Kill(os.Getpid(), syscall.SIGTERM); err != nil { 85 t.Fatalf("send SIGTERM: %v", err) 86 } 87 select { 88 case <-done: 89 case <-time.After(3 * time.Second): 90 t.Fatalf("main did not shut down in time; logs: %q", buf.String()) 91 } 92 }