1: <?php
2:
3: namespace GeoIp2\Test\WebService;
4:
5: use Composer\CaBundle\CaBundle;
6: use MaxMind\WebService\Client as WsClient;
7:
8: 9: 10:
11: class ClientTest extends \PHPUnit_Framework_TestCase
12: {
13: private $country = [
14: 'continent' => [
15: 'code' => 'NA',
16: 'geoname_id' => 42,
17: 'names' => ['en' => 'North America'],
18: ],
19: 'country' => [
20: 'geoname_id' => 1,
21: 'iso_code' => 'US',
22: 'names' => ['en' => 'United States of America'],
23: ],
24: 'maxmind' => ['queries_remaining' => 11],
25: 'traits' => [
26: 'ip_address' => '1.2.3.4',
27: ],
28: ];
29:
30: private function getResponse($ipAddress)
31: {
32: $responses = [
33: '1.2.3.4' => $this->response(
34: 'country',
35: 200,
36: $this->country
37: ),
38: 'me' => $this->response(
39: 'country',
40: 200,
41: $this->country
42: ),
43: '1.2.3.5' => $this->response('country', 200),
44: '2.2.3.5' => $this->response('country', 200, 'bad body'),
45: '1.2.3.6' => $this->response(
46: 'error',
47: 400,
48: [
49: 'code' => 'IP_ADDRESS_INVALID',
50: 'error' => 'The value "1.2.3" is not a valid ip address',
51: ]
52: ),
53: '1.2.3.7' => $this->response(
54: 'error',
55: 400
56: ),
57: '1.2.3.8' => $this->response(
58: 'error',
59: 400,
60: ['weird' => 42]
61: ),
62: '1.2.3.9' => $this->response(
63: 'error',
64: 400,
65: null,
66: 'bad body'
67: ),
68: '1.2.3.10' => $this->response(
69: null,
70: 500
71: ),
72: '1.2.3.11' => $this->response(
73: null,
74: 300
75: ),
76: '1.2.3.12' => $this->response(
77: 'error',
78: 406,
79: 'Cannot satisfy your Accept-Charset requirements',
80: null,
81: 'text/plain'
82: ),
83: '1.2.3.13' => $this->response(
84: 'error',
85: 404,
86: [
87: 'code' => 'IP_ADDRESS_NOT_FOUND',
88: 'error' => 'The address "1.2.3.13" is not in our database.',
89: ]
90: ),
91: '1.2.3.14' => $this->response(
92: 'error',
93: 400,
94: [
95: 'code' => 'IP_ADDRESS_RESERVED',
96: 'error' => 'The address "1.2.3.14" is a private address.',
97: ]
98: ),
99: '1.2.3.15' => $this->response(
100: 'error',
101: 401,
102: [
103: 'code' => 'AUTHORIZATION_INVALID',
104: 'error' => 'A user ID and license key are required to use this service',
105: ]
106: ),
107: '1.2.3.16' => $this->response(
108: 'error',
109: 401,
110: [
111: 'code' => 'LICENSE_KEY_REQUIRED',
112: 'error' => 'A license key is required to use this service',
113: ]
114: ),
115: '1.2.3.17' => $this->response(
116: 'error',
117: 401,
118: [
119: 'code' => 'USER_ID_REQUIRED',
120: 'error' => 'A user ID is required to use this service',
121: ]
122: ),
123: '1.2.3.18' => $this->response(
124: 'error',
125: 402,
126: [
127: 'code' => 'OUT_OF_QUERIES',
128: 'error' => 'The license key you have provided is out of queries.',
129: ]
130: ),
131: ];
132:
133: return $responses[$ipAddress];
134: }
135:
136: public function testCountry()
137: {
138: $country = $this->makeRequest('Country', '1.2.3.4');
139:
140: $this->assertInstanceOf('GeoIp2\Model\Country', $country);
141:
142: $this->assertSame(
143: 42,
144: $country->continent->geonameId,
145: 'continent geoname_id is 42'
146: );
147:
148: $this->assertSame(
149: 'NA',
150: $country->continent->code,
151: 'continent code is NA'
152: );
153:
154: $this->assertSame(
155: ['en' => 'North America'],
156: $country->continent->names,
157: 'continent names'
158: );
159:
160: $this->assertSame(
161: 'North America',
162: $country->continent->name,
163: 'continent name is North America'
164: );
165:
166: $this->assertSame(
167: 1,
168: $country->country->geonameId,
169: 'country geoname_id is 1'
170: );
171:
172: $this->assertFalse(
173: $country->country->isInEuropeanUnion,
174: 'country is_in_european_union is false'
175: );
176:
177: $this->assertSame(
178: 'US',
179: $country->country->isoCode,
180: 'country iso_code is US'
181: );
182:
183: $this->assertSame(
184: ['en' => 'United States of America'],
185: $country->country->names,
186: 'country names'
187: );
188:
189: $this->assertSame(
190: 'United States of America',
191: $country->country->name,
192: 'country name is United States of America'
193: );
194:
195: $this->assertSame(
196: 11,
197: $country->maxmind->queriesRemaining,
198: 'queriesRemaining is correct'
199: );
200:
201: $this->assertFalse(
202: $country->registeredCountry->isInEuropeanUnion,
203: 'registered_country is_in_european_union is false'
204: );
205: }
206:
207: public function testInsights()
208: {
209: $record = $this->makeRequest('Insights', '1.2.3.4');
210:
211: $this->assertInstanceOf('GeoIp2\Model\Insights', $record);
212:
213: $this->assertSame(
214: 42,
215: $record->continent->geonameId,
216: 'continent geoname_id is 42'
217: );
218: }
219:
220: public function testCity()
221: {
222: $city = $this->makeRequest('City', '1.2.3.4');
223:
224: $this->assertInstanceOf('GeoIp2\Model\City', $city);
225: }
226:
227: public function testMe()
228: {
229: $city = $this->makeRequest('City', 'me');
230:
231: $this->assertInstanceOf(
232: 'GeoIp2\Model\City',
233: $city,
234: 'can set ip parameter to me'
235: );
236: }
237:
238: 239: 240: 241:
242: public function testNoBodyException()
243: {
244: $this->makeRequest('Country', '1.2.3.5');
245: }
246:
247: 248: 249: 250:
251: public function testBadBodyException()
252: {
253: $this->makeRequest('Country', '2.2.3.5');
254: }
255:
256: 257: 258: 259: 260:
261: public function testInvalidIPException()
262: {
263: $this->makeRequest('Country', '1.2.3.6');
264: }
265:
266: 267: 268: 269: 270:
271: public function testNoErrorBodyIPException()
272: {
273: $this->makeRequest('Country', '1.2.3.7');
274: }
275:
276: 277: 278: 279:
280: public function testWeirdErrorBodyIPException()
281: {
282: $this->makeRequest('Country', '1.2.3.8');
283: }
284:
285: 286: 287: 288: 289:
290: public function testInvalidErrorBodyIPException()
291: {
292: $this->makeRequest('Country', '1.2.3.9');
293: }
294:
295: 296: 297: 298: 299:
300: public function test500PException()
301: {
302: $this->makeRequest('Country', '1.2.3.10');
303: }
304:
305: 306: 307: 308: 309:
310: public function test3xxException()
311: {
312: $this->makeRequest('Country', '1.2.3.11');
313: }
314:
315: 316: 317: 318: 319:
320: public function test406Exception()
321: {
322: $this->makeRequest('Country', '1.2.3.12');
323: }
324:
325: 326: 327: 328:
329: public function testAddressNotFoundException()
330: {
331: $this->makeRequest('Country', '1.2.3.13');
332: }
333:
334: 335: 336: 337:
338: public function testAddressReservedException()
339: {
340: $this->makeRequest('Country', '1.2.3.14');
341: }
342:
343: 344: 345: 346:
347: public function testAuthorizationException()
348: {
349: $this->makeRequest('Country', '1.2.3.15');
350: }
351:
352: 353: 354: 355:
356: public function testMissingLicenseKeyException()
357: {
358: $this->makeRequest('Country', '1.2.3.16');
359: }
360:
361: 362: 363: 364:
365: public function testMissingUserIdException()
366: {
367: $this->makeRequest('Country', '1.2.3.17');
368: }
369:
370: 371: 372: 373:
374: public function testOutOfQueriesException()
375: {
376: $this->makeRequest('Country', '1.2.3.18');
377: }
378:
379: public function testParams()
380: {
381: $this->makeRequest(
382: 'Country',
383: '1.2.3.4',
384: ['en'],
385: [
386: 'host' => 'api.maxmind.com',
387: 'timeout' => 27,
388: 'connectTimeout' => 72,
389: ]
390: );
391: }
392:
393: private function response(
394: $endpoint,
395: $status,
396: $body = null,
397: $bad = null,
398: $contentType = null
399: ) {
400: $headers = [];
401: if ($contentType) {
402: $headers['Content-Type'] = $contentType;
403: } elseif ($status === 200 || ($status >= 400 && $status < 500)) {
404: $headers['Content-Type'] = 'application/vnd.maxmind.com-'
405: . $endpoint . '+json; charset=UTF-8; version=1.0;';
406: }
407:
408: if ($bad) {
409: $body = '{ invalid: }';
410: } elseif (is_array($body)) {
411: $body = json_encode($body);
412: }
413:
414: $headers['Content-Length'] = strlen($body);
415:
416: return [$status, $headers, $body];
417: }
418:
419: private function makeRequest(
420: $service,
421: $ipAddress,
422: $locales = ['en'],
423: $options = [],
424: $callsToRequest = 1
425: ) {
426: $userId = 42;
427: $licenseKey = 'abcdef123456';
428:
429: list($statusCode, $headers, $responseBody)
430: = $this->getResponse($ipAddress);
431:
432: $stub = $this->getMockForAbstractClass(
433: 'MaxMind\\WebService\\Http\\Request'
434: );
435: $contentType = isset($headers['Content-Type'])
436: ? $headers['Content-Type']
437: : null;
438: $stub->expects($this->exactly($callsToRequest))
439: ->method('get')
440: ->willReturn([$statusCode, $contentType, $responseBody]);
441: $factory = $this->getMockBuilder(
442: 'MaxMind\\WebService\\Http\\RequestFactory'
443: )->getMock();
444: $host = isset($options['host']) ? $options['host'] : 'geoip.maxmind.com';
445: $url = 'https://' . $host . '/geoip/v2.1/' . strtolower($service)
446: . '/' . $ipAddress;
447: $headers = [
448: 'Authorization: Basic '
449: . base64_encode($userId . ':' . $licenseKey),
450: 'Accept: application/json',
451: ];
452:
453: $caBundle = CaBundle::getSystemCaRootBundlePath();
454:
455: $curlVersion = curl_version();
456: $factory->expects($this->exactly($callsToRequest))
457: ->method('request')
458: ->with(
459: $this->equalTo($url),
460: $this->equalTo(
461: [
462: 'headers' => $headers,
463: 'userAgent' => 'GeoIP2-API/' . \GeoIp2\WebService\Client::VERSION
464: . ' MaxMind-WS-API/' . WsClient::VERSION
465: . ' PHP/' . PHP_VERSION
466: . ' curl/' . $curlVersion['version'],
467: 'connectTimeout' => isset($options['connectTimeout'])
468: ? $options['connectTimeout'] : null,
469: 'timeout' => isset($options['timeout'])
470: ? $options['timeout'] : null,
471: 'proxy' => isset($options['proxy'])
472: ? $options['proxy'] : null,
473: 'caBundle' => $caBundle,
474: ]
475: )
476: )->willReturn($stub);
477: $options['httpRequestFactory'] = $factory;
478:
479: $method = strtolower($service);
480:
481: $client = new \GeoIp2\WebService\Client(
482: $userId,
483: $licenseKey,
484: $locales,
485: $options
486: );
487:
488: return $client->$method($ipAddress);
489: }
490: }
491: