refactor: dependency injection instead of package globals (#57)

* refactor: export Settings type, Setup returns value

* refactor: resolver.Setup takes explicit Settings struct

* refactor: GetHeadersWithoutTrustedHeaders takes explicit header params

* refactor: server constructors take narrow config

* refactor: Router struct with handler methods, remove geoSvc global

* refactor: wire DI through main, remove setting.App references

* refactor: remove App global, use returned Settings

* refactor: update router tests for DI

* chore: fix lint issues — rename ServerTimeouts to Timeouts, fix shadowed variables
This commit is contained in:
2026-07-21 18:37:21 +02:00
committed by GitHub
parent 3874f6af3f
commit 2e32a20f60
19 changed files with 298 additions and 253 deletions
+29 -41
View File
@@ -1,12 +1,14 @@
package router
import (
"context"
"net"
"net/http"
"net/http/httptest"
"testing"
"github.com/dcarrillo/whatismyip/internal/setting"
"github.com/dcarrillo/whatismyip/service"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
)
@@ -99,8 +101,9 @@ func TestHost(t *testing.T) {
func TestClientPort(t *testing.T) {
type args struct {
params []string
headers map[string][]string
trustedHeader string
trustedPortHeader string
headers map[string][]string
}
tests := []struct {
name string
@@ -114,35 +117,23 @@ func TestClientPort(t *testing.T) {
{
name: "Trusted header only set",
args: args{
params: []string{
"-geoip2-city", "city",
"-geoip2-asn", "asn",
"-trusted-header", trustedHeader,
},
trustedHeader: trustedHeader,
},
expected: "unknown\n",
},
{
name: "Trusted and port header set but not included in headers",
args: args{
params: []string{
"-geoip2-city", "city",
"-geoip2-asn", "asn",
"-trusted-header", trustedHeader,
"-trusted-port-header", trustedPortHeader,
},
trustedHeader: trustedHeader,
trustedPortHeader: trustedPortHeader,
},
expected: "unknown\n",
},
{
name: "Trusted and port header set and included in headers",
args: args{
params: []string{
"-geoip2-city", "city",
"-geoip2-asn", "asn",
"-trusted-header", trustedHeader,
"-trusted-port-header", trustedPortHeader,
},
trustedHeader: trustedHeader,
trustedPortHeader: trustedPortHeader,
headers: map[string][]string{
trustedHeader: {testIP.ipv4},
trustedPortHeader: {"1001"},
@@ -153,19 +144,22 @@ func TestClientPort(t *testing.T) {
}
for _, tt := range tests {
_, _ = setting.Setup(tt.args.params)
t.Run(tt.name, func(t *testing.T) {
engine := gin.Default()
engine.TrustedPlatform = tt.args.trustedHeader
r := NewRouter(nil, tt.args.trustedHeader, tt.args.trustedPortHeader, "", false)
Setup(engine, r)
req, _ := http.NewRequest("GET", "/client-port", nil)
req.RemoteAddr = net.JoinHostPort(testIP.ipv4, "1000")
req.Header = tt.args.headers
w := httptest.NewRecorder()
app.ServeHTTP(w, req)
engine.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
assert.Equal(t, contentType.text, w.Header().Get("Content-Type"))
assert.Equal(t, tt.expected, w.Body.String())
t.Log(w.Header())
})
}
}
@@ -181,14 +175,11 @@ func TestNotFound(t *testing.T) {
}
func TestJSON(t *testing.T) {
_, _ = setting.Setup(
[]string{
"-geoip2-city", "city",
"-geoip2-asn", "asn",
"-trusted-header", trustedHeader,
"-trusted-port-header", trustedPortHeader,
},
)
svc, _ := service.NewGeo(context.Background(), "../test/GeoIP2-City-Test.mmdb", "../test/GeoLite2-ASN-Test.mmdb")
engine := gin.Default()
engine.TrustedPlatform = trustedHeader
r := NewRouter(svc, trustedHeader, trustedPortHeader, "", false)
Setup(engine, r)
type args struct {
ip string
@@ -222,7 +213,7 @@ func TestJSON(t *testing.T) {
req.Header.Set(trustedPortHeader, "1001")
w := httptest.NewRecorder()
app.ServeHTTP(w, req)
engine.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
assert.Equal(t, contentType.json, w.Header().Get("Content-Type"))
@@ -248,14 +239,11 @@ ASN Organization:
Header1: one
Host: test
`
_, _ = setting.Setup(
[]string{
"-geoip2-city", "city",
"-geoip2-asn", "asn",
"-trusted-header", trustedHeader,
"-trusted-port-header", trustedPortHeader,
},
)
svc, _ := service.NewGeo(context.Background(), "../test/GeoIP2-City-Test.mmdb", "../test/GeoLite2-ASN-Test.mmdb")
engine := gin.Default()
engine.TrustedPlatform = trustedHeader
r := NewRouter(svc, trustedHeader, trustedPortHeader, "", false)
Setup(engine, r)
req, _ := http.NewRequest("GET", "/all", nil)
req.RemoteAddr = net.JoinHostPort(testIP.ipv4, "1000")
@@ -265,7 +253,7 @@ Host: test
req.Header.Set("Header1", "one")
w := httptest.NewRecorder()
app.ServeHTTP(w, req)
engine.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
assert.Equal(t, contentType.text, w.Header().Get("Content-Type"))