github.com/m-lab/locate@v0.17.6/clientgeo/maxmind_test.go (about) 1 package clientgeo 2 3 import ( 4 "context" 5 "errors" 6 "net/http" 7 "net/http/httptest" 8 "net/url" 9 "reflect" 10 "testing" 11 12 "github.com/m-lab/go/content" 13 "github.com/m-lab/go/rtx" 14 ) 15 16 // Networks taken from https://github.com/maxmind/MaxMind-DB/blob/master/source-data/GeoIP2-City-Test.json 17 var localIP = "175.16.199.3" 18 var remoteIP = "2.125.160.216" // includes multiple subdivision annotations. 19 20 func TestNewMaxmindLocator(t *testing.T) { 21 var localRawfile content.Provider 22 23 tests := []struct { 24 name string 25 useHeaders map[string]string 26 remoteIP string 27 want *Location 28 filename string 29 reloadDB bool 30 wantErr bool 31 }{ 32 { 33 name: "success-using-X-Forwarded-For-header", 34 useHeaders: map[string]string{ 35 "X-Forwarded-For": "2.125.160.216, 192.168.0.2", 36 }, 37 remoteIP: remoteIP + ":1234", 38 want: &Location{ 39 Latitude: "51.750000", 40 Longitude: "-1.250000", 41 Headers: http.Header{ 42 hLocateClientlatlon: []string{"51.750000,-1.250000"}, 43 hLocateClientlatlonMethod: []string{"maxmind-remoteip"}, 44 }, 45 }, 46 filename: "file:./testdata/fake.tar.gz", 47 }, 48 { 49 name: "success-using-remote-ip", 50 remoteIP: remoteIP + ":1234", 51 want: &Location{ 52 Latitude: "51.750000", 53 Longitude: "-1.250000", 54 Headers: http.Header{ 55 hLocateClientlatlon: []string{"51.750000,-1.250000"}, 56 hLocateClientlatlonMethod: []string{"maxmind-remoteip"}, 57 }, 58 }, 59 filename: "file:./testdata/fake.tar.gz", 60 }, 61 { 62 name: "error-remote-ip-split-error", 63 remoteIP: "invalid-ip-1234", 64 filename: "file:./testdata/fake.tar.gz", 65 wantErr: true, 66 }, 67 { 68 name: "error-remote-ip-parses-as-nil", 69 remoteIP: "invalid-ip:1234", 70 filename: "file:./testdata/fake.tar.gz", 71 wantErr: true, 72 }, 73 { 74 name: "error-maxmind-db-error", 75 remoteIP: remoteIP + ":1234", 76 reloadDB: true, 77 filename: "file:./testdata/fake.tar.gz", 78 wantErr: true, 79 }, 80 { 81 name: "error-wrong-db-type", 82 remoteIP: "127.0.0.1:1234", 83 filename: "file:./testdata/wrongtype.tar.gz", 84 wantErr: true, 85 }, 86 { 87 name: "error-empty-response-from-db", 88 remoteIP: "127.0.0.1:1234", 89 filename: "file:./testdata/fake.tar.gz", 90 wantErr: true, 91 }, 92 } 93 for _, tt := range tests { 94 t.Run(tt.name, func(t *testing.T) { 95 u, err := url.Parse(tt.filename) 96 rtx.Must(err, "Could not parse URL") 97 localRawfile, err = content.FromURL(context.Background(), u) 98 rtx.Must(err, "Could not create content.Provider") 99 100 ctx := context.Background() 101 locator := NewMaxmindLocator(ctx, localRawfile) 102 if tt.reloadDB { 103 // This will result in a null maxmind db, b/c the localRawfile has not changed. 104 locator = NewMaxmindLocator(ctx, localRawfile) 105 } 106 107 req := httptest.NewRequest(http.MethodGet, "/anytarget", nil) 108 for key, value := range tt.useHeaders { 109 req.Header.Set(key, value) 110 } 111 req.RemoteAddr = tt.remoteIP 112 113 l, err := locator.Locate(req) 114 if (err != nil) && !tt.wantErr { 115 t.Errorf("MaxmindLocator.Locate got error: %v", err) 116 } 117 // fmt.Printf("%#v\n", l) 118 if !reflect.DeepEqual(l, tt.want) { 119 t.Errorf("NewMaxmindLocator() = %v, want %v", l, tt.want) 120 } 121 }) 122 } 123 } 124 125 // workOnceProvider returns an error the second reload. 126 type workOnceProvider struct { 127 provider content.Provider 128 called bool 129 } 130 131 func (w *workOnceProvider) Get(ctx context.Context) ([]byte, error) { 132 if !w.called { 133 w.called = true 134 return w.provider.Get(ctx) 135 } 136 return nil, errors.New("fake error on second load") 137 } 138 139 // emptyReloadProvider returns an empty archive on the second reload. 140 type emptyReloadProvider struct { 141 provider content.Provider 142 called bool 143 } 144 145 func (e *emptyReloadProvider) Get(ctx context.Context) ([]byte, error) { 146 if !e.called { 147 e.called = true 148 return e.provider.Get(ctx) 149 } 150 return []byte("bad-content"), nil 151 } 152 153 func loadProvider(name string) content.Provider { 154 u, err := url.Parse(name) 155 rtx.Must(err, "Could not parse URL") 156 localRawfile, err := content.FromURL(context.Background(), u) 157 rtx.Must(err, "Could not create content.Provider") 158 return localRawfile 159 } 160 161 func TestMaxmindLocator_Reload(t *testing.T) { 162 tests := []struct { 163 name string 164 workOnce bool 165 emptyAfter bool 166 }{ 167 { 168 name: "success", 169 }, 170 { 171 name: "success-fail-second-reload-error", 172 workOnce: true, 173 }, 174 { 175 name: "success-fail-second-reload-data", 176 emptyAfter: true, 177 }, 178 } 179 for _, tt := range tests { 180 t.Run(tt.name, func(t *testing.T) { 181 182 localRawfile := loadProvider("file:./testdata/fake.tar.gz") 183 184 if tt.workOnce { 185 localRawfile = &workOnceProvider{ 186 provider: localRawfile, 187 } 188 } 189 if tt.emptyAfter { 190 localRawfile = &emptyReloadProvider{ 191 provider: localRawfile, 192 } 193 } 194 195 ctx := context.Background() 196 mml := NewMaxmindLocator(ctx, localRawfile) 197 mml.Reload(ctx) 198 }) 199 } 200 }