first commit
This commit is contained in:
175
internal/httpapi/server_test.go
Normal file
175
internal/httpapi/server_test.go
Normal file
@@ -0,0 +1,175 @@
|
||||
package httpapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"ipecho/internal/clientip"
|
||||
)
|
||||
|
||||
func TestIPEndpointReturnsPlainTextClientIP(t *testing.T) {
|
||||
handler := New(clientip.Resolver{})
|
||||
req := httptest.NewRequest(http.MethodGet, "/ip", nil)
|
||||
req.RemoteAddr = "198.51.100.20:54123"
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
handler.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("got status %d, want %d", rec.Code, http.StatusOK)
|
||||
}
|
||||
|
||||
if got, want := rec.Body.String(), "198.51.100.20\n"; got != want {
|
||||
t.Fatalf("got body %q, want %q", got, want)
|
||||
}
|
||||
|
||||
if got := rec.Header().Get("Content-Type"); !strings.HasPrefix(got, "text/plain") {
|
||||
t.Fatalf("got content-type %q, want text/plain", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRootReturnsPlainTextClientIPForCLIRequests(t *testing.T) {
|
||||
handler := New(clientip.Resolver{})
|
||||
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||
req.RemoteAddr = "198.51.100.20:54123"
|
||||
req.Header.Set("Accept", "*/*")
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
handler.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("got status %d, want %d", rec.Code, http.StatusOK)
|
||||
}
|
||||
|
||||
if got, want := rec.Body.String(), "198.51.100.20\n"; got != want {
|
||||
t.Fatalf("got body %q, want %q", got, want)
|
||||
}
|
||||
|
||||
if got := rec.Header().Get("Content-Type"); !strings.HasPrefix(got, "text/plain") {
|
||||
t.Fatalf("got content-type %q, want text/plain", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRootReturnsHTMLForBrowserRequests(t *testing.T) {
|
||||
handler := New(clientip.Resolver{})
|
||||
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||
req.RemoteAddr = "198.51.100.20:54123"
|
||||
req.Header.Set("Accept", "text/html,application/xhtml+xml")
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
handler.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("got status %d, want %d", rec.Code, http.StatusOK)
|
||||
}
|
||||
|
||||
if got := rec.Header().Get("Content-Type"); !strings.HasPrefix(got, "text/html") {
|
||||
t.Fatalf("got content-type %q, want text/html", got)
|
||||
}
|
||||
|
||||
body := rec.Body.String()
|
||||
for _, want := range []string{"IP Echo", "198.51.100.20", "Copy IP", "/json"} {
|
||||
if !strings.Contains(body, want) {
|
||||
t.Fatalf("body does not contain %q", want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONEndpointReturnsRequestMetadata(t *testing.T) {
|
||||
handler := New(clientip.Resolver{TrustProxyHeaders: true})
|
||||
req := httptest.NewRequest(http.MethodGet, "/json", nil)
|
||||
req.RemoteAddr = "198.51.100.20:54123"
|
||||
req.Header.Set("User-Agent", "ipecho-test")
|
||||
req.Header.Set("X-Forwarded-For", "203.0.113.10")
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
handler.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("got status %d, want %d", rec.Code, http.StatusOK)
|
||||
}
|
||||
|
||||
var got ClientInfo
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &got); err != nil {
|
||||
t.Fatalf("decode response: %v", err)
|
||||
}
|
||||
|
||||
if got.IP != "203.0.113.10" {
|
||||
t.Fatalf("got ip %q, want %q", got.IP, "203.0.113.10")
|
||||
}
|
||||
|
||||
if got.UserAgent != "ipecho-test" {
|
||||
t.Fatalf("got user agent %q, want %q", got.UserAgent, "ipecho-test")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHeadersEndpointIncludesHostAndHeaders(t *testing.T) {
|
||||
handler := New(clientip.Resolver{})
|
||||
req := httptest.NewRequest(http.MethodGet, "/headers", nil)
|
||||
req.Host = "example.test"
|
||||
req.Header.Set("User-Agent", "ipecho-test")
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
handler.ServeHTTP(rec, req)
|
||||
|
||||
body := rec.Body.String()
|
||||
for _, want := range []string{"Host: example.test", "User-Agent: ipecho-test"} {
|
||||
if !strings.Contains(body, want) {
|
||||
t.Fatalf("body %q does not contain %q", body, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFaviconEndpointReturnsIconWithoutHTMLLink(t *testing.T) {
|
||||
handler := New(clientip.Resolver{})
|
||||
req := httptest.NewRequest(http.MethodGet, "/favicon.ico", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
handler.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("got status %d, want %d", rec.Code, http.StatusOK)
|
||||
}
|
||||
|
||||
if got := rec.Header().Get("Content-Type"); got != "image/x-icon" {
|
||||
t.Fatalf("got content-type %q, want image/x-icon", got)
|
||||
}
|
||||
|
||||
if rec.Body.Len() == 0 {
|
||||
t.Fatal("favicon response is empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSecurityHeadersAreApplied(t *testing.T) {
|
||||
handler := New(clientip.Resolver{})
|
||||
req := httptest.NewRequest(http.MethodGet, "/healthz", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
handler.ServeHTTP(rec, req)
|
||||
|
||||
for _, header := range []string{
|
||||
"X-Content-Type-Options",
|
||||
"X-Frame-Options",
|
||||
"Referrer-Policy",
|
||||
"Content-Security-Policy",
|
||||
} {
|
||||
if rec.Header().Get(header) == "" {
|
||||
t.Fatalf("missing %s header", header)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnknownEndpointReturnsNotFound(t *testing.T) {
|
||||
handler := New(clientip.Resolver{})
|
||||
req := httptest.NewRequest(http.MethodGet, "/missing", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
handler.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusNotFound {
|
||||
t.Fatalf("got status %d, want %d", rec.Code, http.StatusNotFound)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user