package geoip import ( "strings" "testing" "time" ) const sha = "9f2c000000000000000000000000000000000000000000000000000000000001" func TestParsePointerAcceptsTheSpecShape(t *testing.T) { raw := `{"v":1,"sha256":"` + sha + `","key":"control/geoip/` + sha + `.mmdb","size":10, "database_type":"DBIP-City-Lite","build_epoch":1790812800,"node_count":7, "published":"2026-10-06T21:00:00Z","origin":"manual","edition":""}` p, err := ParsePointer([]byte(raw)) if err != nil { t.Fatal(err) } if p.Key != BlobKey(sha) || p.Size != 10 || p.DatabaseType != "DBIP-City-Lite" || p.Build().Unix() != 1790812800 { t.Fatalf("pointer = %+v", p) } } func TestParsePointerRefusesWhatAnEdgeMustNotFollow(t *testing.T) { good := `"sha256":"` + sha + `","key":"control/geoip/` + sha + `.mmdb","size":10,"database_type":"X","build_epoch":1` bad := map[string]string{ "unknown version": `{"v":2,` + good + `}`, "short sha": `{"v":1,"sha256":"9f","key":"control/geoip/9f.mmdb","size":1,"database_type":"X","build_epoch":1}`, "key not the blob key": `{"v":1,"sha256":"` + sha + `","key":"apps/x/secret","size":10,"database_type":"X","build_epoch":1}`, "zero size": `{"v":1,"sha256":"` + sha + `","key":"control/geoip/` + sha + `.mmdb","size":0,"database_type":"X","build_epoch":1}`, "oversize": `{"v":1,"sha256":"` + sha + `","key":"control/geoip/` + sha + `.mmdb","size":1073741825,"database_type":"X","build_epoch":1}`, "not json": `nope`, } for name, raw := range bad { if _, err := ParsePointer([]byte(raw)); err == nil { t.Errorf("%s: accepted", name) } } } func TestGeoLiteExpiresThirtyDaysAfterBuild(t *testing.T) { build := time.Date(2026, 9, 1, 0, 0, 0, 0, time.UTC) at, ok := ExpiresAt("GeoLite2-City", build) if !ok || !at.Equal(build.Add(30*24*time.Hour)) { t.Fatalf("ExpiresAt = (%v, %v)", at, ok) } if Expired("GeoLite2-City", build, build.Add(30*24*time.Hour-time.Second)) { t.Fatal("expired a second early") } if !Expired("GeoLite2-Country", build, build.Add(30*24*time.Hour)) { t.Fatal("not expired at 30 days") } if Expired("DBIP-City-Lite", build, build.Add(400*24*time.Hour)) { t.Fatal("DB-IP must never expire (D1)") } if _, ok := ExpiresAt("GeoIP2-City", build); ok { t.Fatal("only GeoLite2- expires") } } func TestAttributionTable(t *testing.T) { if a, ok := AttributionFor("DBIP-City-Lite"); !ok || a.Text != "IP Geolocation by DB-IP" || a.URL != "https://db-ip.com" { t.Fatalf("dbip = %+v %v", a, ok) } if a, ok := AttributionFor("GeoLite2-Country"); !ok || !strings.Contains(a.Text, "GeoLite2 data created by MaxMind") { t.Fatalf("geolite = %+v %v", a, ok) } if _, ok := AttributionFor("GeoIP2-City"); ok { t.Fatal("no attribution is known for commercial GeoIP2; the operator's licence governs") } }