PageRenderTime 49ms CodeModel.GetById 10ms app.highlight 34ms RepoModel.GetById 2ms app.codeStats 0ms

/Godeps/_workspace/src/github.com/oschwald/maxminddb-golang/reader_test.go

https://gitlab.com/voxxit/gogeoip2
Go | 398 lines | 335 code | 63 blank | 0 comment | 61 complexity | a859b4399e8c4c63ea4f8e720f119cf7 MD5 | raw file
  1package maxminddb
  2
  3import (
  4	"errors"
  5	"fmt"
  6	"io/ioutil"
  7	"math/big"
  8	"math/rand"
  9	"net"
 10	"testing"
 11	"time"
 12
 13	. "gopkg.in/check.v1"
 14)
 15
 16func TestMaxMindDbReader(t *testing.T) { TestingT(t) }
 17
 18type MySuite struct{}
 19
 20var _ = Suite(&MySuite{})
 21
 22func (s *MySuite) TestReader(c *C) {
 23	for _, recordSize := range []uint{24, 28, 32} {
 24		for _, ipVersion := range []uint{4, 6} {
 25			fileName := fmt.Sprintf("test-data/test-data/MaxMind-DB-test-ipv%d-%d.mmdb", ipVersion, recordSize)
 26			reader, err := Open(fileName)
 27			if err != nil {
 28				c.Logf("unexpected error while opening database: %v", err)
 29				c.Fail()
 30			}
 31
 32			checkMetadata(c, reader, ipVersion, recordSize)
 33
 34			if ipVersion == 4 {
 35				checkIpv4(c, reader)
 36			} else {
 37				checkIpv6(c, reader)
 38			}
 39		}
 40	}
 41}
 42
 43func (s *MySuite) TestReaderBytes(c *C) {
 44	for _, recordSize := range []uint{24, 28, 32} {
 45		for _, ipVersion := range []uint{4, 6} {
 46			fileName := fmt.Sprintf("test-data/test-data/MaxMind-DB-test-ipv%d-%d.mmdb", ipVersion, recordSize)
 47			bytes, _ := ioutil.ReadFile(fileName)
 48			reader, err := FromBytes(bytes)
 49			if err != nil {
 50				c.Logf("unexpected error while opening bytes: %v", err)
 51				c.Fail()
 52			}
 53
 54			checkMetadata(c, reader, ipVersion, recordSize)
 55
 56			if ipVersion == 4 {
 57				checkIpv4(c, reader)
 58			} else {
 59				checkIpv6(c, reader)
 60			}
 61		}
 62	}
 63}
 64
 65func (s *MySuite) TestDecodingToInterface(c *C) {
 66	reader, err := Open("test-data/test-data/MaxMind-DB-test-decoder.mmdb")
 67	if err != nil {
 68		c.Logf("unexpected error while opening database: %v", err)
 69		c.Fail()
 70	}
 71
 72	var recordInterface interface{}
 73	err = reader.Lookup(net.ParseIP("::1.1.1.0"), &recordInterface)
 74	if err != nil {
 75		c.Logf("unexpected error while doing lookup: %v", err)
 76		c.Fail()
 77	}
 78	record := recordInterface.(map[string]interface{})
 79
 80	c.Assert(record["array"], DeepEquals, []interface{}{uint64(1), uint64(2), uint64(3)})
 81	c.Assert(record["boolean"], Equals, true)
 82	c.Assert(record["bytes"], DeepEquals, []byte{0x00, 0x00, 0x00, 0x2a})
 83	c.Assert(record["double"], Equals, 42.123456)
 84	c.Assert(record["float"], Equals, float32(1.1))
 85	c.Assert(record["int32"], Equals, -268435456)
 86	c.Assert(record["map"], DeepEquals,
 87		map[string]interface{}{
 88			"mapX": map[string]interface{}{
 89				"arrayX":       []interface{}{uint64(7), uint64(8), uint64(9)},
 90				"utf8_stringX": "hello",
 91			}})
 92
 93	c.Assert(record["uint16"], Equals, uint64(100))
 94	c.Assert(record["uint32"], Equals, uint64(268435456))
 95	c.Assert(record["uint64"], Equals, uint64(1152921504606846976))
 96	c.Assert(record["utf8_string"], Equals, "unicode! ☯ - ♫")
 97	bigInt := new(big.Int)
 98	bigInt.SetString("1329227995784915872903807060280344576", 10)
 99	c.Assert(record["uint128"], DeepEquals, bigInt)
100}
101
102type TestType struct {
103	Array      []uint                 `maxminddb:"array"`
104	Boolean    bool                   `maxminddb:"boolean"`
105	Bytes      []byte                 `maxminddb:"bytes"`
106	Double     float64                `maxminddb:"double"`
107	Float      float32                `maxminddb:"float"`
108	Int32      int32                  `maxminddb:"int32"`
109	Map        map[string]interface{} `maxminddb:"map"`
110	Uint16     uint16                 `maxminddb:"uint16"`
111	Uint32     uint32                 `maxminddb:"uint32"`
112	Uint64     uint64                 `maxminddb:"uint64"`
113	Uint128    big.Int                `maxminddb:"uint128"`
114	Utf8String string                 `maxminddb:"utf8_string"`
115}
116
117func (s *MySuite) TestDecoder(c *C) {
118	reader, err := Open("test-data/test-data/MaxMind-DB-test-decoder.mmdb")
119	if err != nil {
120		c.Logf("unexpected error while opening database: %v", err)
121		c.Fail()
122	}
123
124	var result TestType
125	err = reader.Lookup(net.ParseIP("::1.1.1.0"), &result)
126	if err != nil {
127		c.Log(err)
128		c.Fail()
129	}
130
131	c.Assert(result.Array, DeepEquals, []uint{uint(1), uint(2), uint(3)})
132	c.Assert(result.Boolean, Equals, true)
133	c.Assert(result.Bytes, DeepEquals, []byte{0x00, 0x00, 0x00, 0x2a})
134	c.Assert(result.Double, Equals, 42.123456)
135	c.Assert(result.Float, Equals, float32(1.1))
136	c.Assert(result.Int32, Equals, int32(-268435456))
137
138	c.Assert(result.Map, DeepEquals,
139		map[string]interface{}{
140			"mapX": map[string]interface{}{
141				"arrayX":       []interface{}{uint64(7), uint64(8), uint64(9)},
142				"utf8_stringX": "hello",
143			}})
144
145	c.Assert(result.Uint16, Equals, uint16(100))
146	c.Assert(result.Uint32, Equals, uint32(268435456))
147	c.Assert(result.Uint64, Equals, uint64(1152921504606846976))
148	c.Assert(result.Utf8String, Equals, "unicode! ☯ - ♫")
149	bigInt := new(big.Int)
150	bigInt.SetString("1329227995784915872903807060280344576", 10)
151	c.Assert(&result.Uint128, DeepEquals, bigInt)
152
153	reader.Close()
154}
155
156func (s *MySuite) TestIpv6inIpv4(c *C) {
157	reader, err := Open("test-data/test-data/MaxMind-DB-test-ipv4-24.mmdb")
158	if err != nil {
159		c.Logf("unexpected error while opening database: %v", err)
160		c.Fail()
161	}
162
163	var result TestType
164	err = reader.Lookup(net.ParseIP("2001::"), &result)
165
166	var emptyResult TestType
167	c.Assert(result, DeepEquals, emptyResult)
168
169	expected := errors.New("error looking up '2001::': you attempted to look up an IPv6 address in an IPv4-only database")
170	c.Assert(err, DeepEquals, expected)
171	reader.Close()
172
173}
174
175func (s *MySuite) TestBrokenDatabase(c *C) {
176	reader, err := Open("test-data/test-data/GeoIP2-City-Test-Broken-Double-Format.mmdb")
177	if err != nil {
178		c.Logf("unexpected error while opening database: %v", err)
179		c.Fail()
180	}
181
182	var result interface{}
183	err = reader.Lookup(net.ParseIP("2001:220::"), &result)
184
185	expected := errors.New("the MaxMind DB file's data section contains bad data (float 64 size of 2)")
186	c.Assert(err, DeepEquals, expected)
187	reader.Close()
188}
189
190func (s *MySuite) TestMissingDatabase(c *C) {
191	reader, err := Open("file-does-not-exist.mmdb")
192	if reader != nil {
193		c.Log("received reader when doing lookups on DB that doesn't exist")
194		c.Fail()
195	}
196	c.Assert(err, ErrorMatches, "open file-does-not-exist.mmdb.*")
197}
198
199func (s *MySuite) TestNonDatabase(c *C) {
200	reader, err := Open("README.md")
201	if reader != nil {
202		c.Log("received reader when doing lookups on DB that doesn't exist")
203		c.Fail()
204	}
205	c.Assert(err.Error(), Equals, "error opening database file: invalid MaxMind DB file")
206}
207
208func (s *MySuite) TestDecodingToNonPointer(c *C) {
209	reader, _ := Open("test-data/test-data/MaxMind-DB-test-decoder.mmdb")
210
211	var recordInterface interface{}
212	err := reader.Lookup(net.ParseIP("::1.1.1.0"), recordInterface)
213	c.Assert(err.Error(), Equals, "result param must be a pointer")
214	reader.Close()
215}
216
217func (s *MySuite) TestNilLookup(c *C) {
218	reader, _ := Open("test-data/test-data/MaxMind-DB-test-decoder.mmdb")
219
220	var recordInterface interface{}
221	err := reader.Lookup(nil, recordInterface)
222	c.Assert(err.Error(), Equals, "ipAddress passed to Lookup cannot be nil")
223	reader.Close()
224}
225
226func checkMetadata(c *C, reader *Reader, ipVersion uint, recordSize uint) {
227	metadata := reader.Metadata
228
229	c.Assert(metadata.BinaryFormatMajorVersion, Equals, uint(2))
230
231	c.Assert(metadata.BinaryFormatMinorVersion, Equals, uint(0))
232	c.Assert(metadata.BuildEpoch, FitsTypeOf, uint(0))
233	c.Assert(metadata.DatabaseType, Equals, "Test")
234
235	c.Assert(metadata.Description, DeepEquals,
236		map[string]string{
237			"en": "Test Database",
238			"zh": "Test Database Chinese",
239		})
240	c.Assert(metadata.IPVersion, Equals, ipVersion)
241	c.Assert(metadata.Languages, DeepEquals, []string{"en", "zh"})
242
243	if ipVersion == 4 {
244		c.Assert(metadata.NodeCount, Equals, uint(37))
245	} else {
246		c.Assert(metadata.NodeCount, Equals, uint(160))
247	}
248
249	c.Assert(metadata.RecordSize, Equals, recordSize)
250}
251
252func checkIpv4(c *C, reader *Reader) {
253
254	for i := uint(0); i < 6; i++ {
255		address := fmt.Sprintf("1.1.1.%d", uint(1)<<i)
256		ip := net.ParseIP(address)
257
258		var result map[string]string
259		err := reader.Lookup(ip, &result)
260		if err != nil {
261			c.Logf("unexpected error while doing lookup: %v", err)
262			c.Fail()
263		}
264		c.Assert(result, DeepEquals, map[string]string{
265			"ip": address})
266	}
267	pairs := map[string]string{
268		"1.1.1.3":  "1.1.1.2",
269		"1.1.1.5":  "1.1.1.4",
270		"1.1.1.7":  "1.1.1.4",
271		"1.1.1.9":  "1.1.1.8",
272		"1.1.1.15": "1.1.1.8",
273		"1.1.1.17": "1.1.1.16",
274		"1.1.1.31": "1.1.1.16",
275	}
276
277	for keyAddress, valueAddress := range pairs {
278		data := map[string]string{"ip": valueAddress}
279
280		ip := net.ParseIP(keyAddress)
281
282		var result map[string]string
283		err := reader.Lookup(ip, &result)
284		if err != nil {
285			c.Logf("unexpected error while doing lookup: %v", err)
286			c.Fail()
287		}
288		c.Assert(result, DeepEquals, data)
289	}
290
291	for _, address := range []string{"1.1.1.33", "255.254.253.123"} {
292		ip := net.ParseIP(address)
293
294		var result map[string]string
295		err := reader.Lookup(ip, &result)
296		if err != nil {
297			c.Logf("unexpected error while doing lookup: %v", err)
298			c.Fail()
299		}
300		c.Assert(result, IsNil)
301	}
302}
303
304func checkIpv6(c *C, reader *Reader) {
305
306	subnets := []string{"::1:ffff:ffff", "::2:0:0",
307		"::2:0:40", "::2:0:50", "::2:0:58"}
308
309	for _, address := range subnets {
310		var result map[string]string
311		err := reader.Lookup(net.ParseIP(address), &result)
312		if err != nil {
313			c.Logf("unexpected error while doing lookup: %v", err)
314			c.Fail()
315		}
316		c.Assert(result, DeepEquals, map[string]string{"ip": address})
317	}
318
319	pairs := map[string]string{
320		"::2:0:1":  "::2:0:0",
321		"::2:0:33": "::2:0:0",
322		"::2:0:39": "::2:0:0",
323		"::2:0:41": "::2:0:40",
324		"::2:0:49": "::2:0:40",
325		"::2:0:52": "::2:0:50",
326		"::2:0:57": "::2:0:50",
327		"::2:0:59": "::2:0:58",
328	}
329
330	for keyAddress, valueAddress := range pairs {
331		data := map[string]string{"ip": valueAddress}
332		var result map[string]string
333		err := reader.Lookup(net.ParseIP(keyAddress), &result)
334		if err != nil {
335			c.Logf("unexpected error while doing lookup: %v", err)
336			c.Fail()
337		}
338		c.Assert(result, DeepEquals, data)
339	}
340
341	for _, address := range []string{"1.1.1.33", "255.254.253.123", "89fa::"} {
342		var result map[string]string
343		err := reader.Lookup(net.ParseIP(address), &result)
344		if err != nil {
345			c.Logf("unexpected error while doing lookup: %v", err)
346			c.Fail()
347		}
348		c.Assert(result, IsNil)
349	}
350}
351
352func BenchmarkMaxMindDB(b *testing.B) {
353	db, err := Open("GeoLite2-City.mmdb")
354	if err != nil {
355		b.Fatal(err)
356	}
357
358	r := rand.New(rand.NewSource(time.Now().UnixNano()))
359	var result interface{}
360
361	for i := 0; i < b.N; i++ {
362		num := r.Uint32()
363		ip := net.ParseIP(fmt.Sprintf("%d.%d.%d.%d", (0xFF000000&num)>>24,
364			(0x00FF0000&num)>>16, (0x0000FF00&num)>>8, 0x000000FF&num))
365		err := db.Lookup(ip, &result)
366		if err != nil {
367			b.Fatal(err)
368		}
369	}
370	db.Close()
371}
372
373func BenchmarkCountryCode(b *testing.B) {
374	db, err := Open("GeoLite2-City.mmdb")
375	if err != nil {
376		b.Fatal(err)
377	}
378
379	type MinCountry struct {
380		Country struct {
381			IsoCode string `maxminddb:"iso_code"`
382		} `maxminddb:"country"`
383	}
384
385	r := rand.New(rand.NewSource(time.Now().UnixNano()))
386	var result MinCountry
387
388	for i := 0; i < b.N; i++ {
389		num := r.Uint32()
390		ip := net.ParseIP(fmt.Sprintf("%d.%d.%d.%d", (0xFF000000&num)>>24,
391			(0x00FF0000&num)>>16, (0x0000FF00&num)>>8, 0x000000FF&num))
392		err := db.Lookup(ip, &result)
393		if err != nil {
394			b.Fatal(err)
395		}
396	}
397	db.Close()
398}