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->assertSame(
173: 'US',
174: $country->country->isoCode,
175: 'country iso_code is US'
176: );
177:
178: $this->assertSame(
179: ['en' => 'United States of America'],
180: $country->country->names,
181: 'country names'
182: );
183:
184: $this->assertSame(
185: 'United States of America',
186: $country->country->name,
187: 'country name is United States of America'
188: );
189:
190: $this->assertSame(
191: 11,
192: $country->maxmind->queriesRemaining,
193: 'queriesRemaining is correct'
194: );
195: }
196:
197: public function testInsights()
198: {
199: $record = $this->makeRequest('Insights', '1.2.3.4');
200:
201: $this->assertInstanceOf('GeoIp2\Model\Insights', $record);
202:
203: $this->assertSame(
204: 42,
205: $record->continent->geonameId,
206: 'continent geoname_id is 42'
207: );
208: }
209:
210: public function testCity()
211: {
212: $city = $this->makeRequest('City', '1.2.3.4');
213:
214: $this->assertInstanceOf('GeoIp2\Model\City', $city);
215: }
216:
217: public function testMe()
218: {
219: $city = $this->makeRequest('City', 'me');
220:
221: $this->assertInstanceOf(
222: 'GeoIp2\Model\City',
223: $city,
224: 'can set ip parameter to me'
225: );
226: }
227:
228: 229: 230: 231:
232: public function testNoBodyException()
233: {
234: $this->makeRequest('Country', '1.2.3.5');
235: }
236:
237: 238: 239: 240:
241: public function testBadBodyException()
242: {
243: $this->makeRequest('Country', '2.2.3.5');
244: }
245:
246: 247: 248: 249: 250:
251: public function testInvalidIPException()
252: {
253: $this->makeRequest('Country', '1.2.3.6');
254: }
255:
256: 257: 258: 259: 260:
261: public function testNoErrorBodyIPException()
262: {
263: $this->makeRequest('Country', '1.2.3.7');
264: }
265:
266: 267: 268: 269:
270: public function testWeirdErrorBodyIPException()
271: {
272: $this->makeRequest('Country', '1.2.3.8');
273: }
274:
275: 276: 277: 278: 279:
280: public function testInvalidErrorBodyIPException()
281: {
282: $this->makeRequest('Country', '1.2.3.9');
283: }
284:
285: 286: 287: 288: 289:
290: public function test500PException()
291: {
292: $this->makeRequest('Country', '1.2.3.10');
293: }
294:
295: 296: 297: 298: 299:
300: public function test3xxException()
301: {
302: $this->makeRequest('Country', '1.2.3.11');
303: }
304:
305: 306: 307: 308: 309:
310: public function test406Exception()
311: {
312: $this->makeRequest('Country', '1.2.3.12');
313: }
314:
315: 316: 317: 318:
319: public function testAddressNotFoundException()
320: {
321: $this->makeRequest('Country', '1.2.3.13');
322: }
323:
324: 325: 326: 327:
328: public function testAddressReservedException()
329: {
330: $this->makeRequest('Country', '1.2.3.14');
331: }
332:
333: 334: 335: 336:
337: public function testAuthorizationException()
338: {
339: $this->makeRequest('Country', '1.2.3.15');
340: }
341:
342: 343: 344: 345:
346: public function testMissingLicenseKeyException()
347: {
348: $this->makeRequest('Country', '1.2.3.16');
349: }
350:
351: 352: 353: 354:
355: public function testMissingUserIdException()
356: {
357: $this->makeRequest('Country', '1.2.3.17');
358: }
359:
360: 361: 362: 363:
364: public function testOutOfQueriesException()
365: {
366: $this->makeRequest('Country', '1.2.3.18');
367: }
368:
369: public function testParams()
370: {
371: $this->makeRequest(
372: 'Country',
373: '1.2.3.4',
374: ['en'],
375: [
376: 'host' => 'api.maxmind.com',
377: 'timeout' => 27,
378: 'connectTimeout' => 72,
379: ]
380: );
381: }
382:
383: private function response(
384: $endpoint,
385: $status,
386: $body = null,
387: $bad = null,
388: $contentType = null
389: ) {
390: $headers = [];
391: if ($contentType) {
392: $headers['Content-Type'] = $contentType;
393: } elseif ($status === 200 || ($status >= 400 && $status < 500)) {
394: $headers['Content-Type'] = 'application/vnd.maxmind.com-'
395: . $endpoint . '+json; charset=UTF-8; version=1.0;';
396: }
397:
398: if ($bad) {
399: $body = '{ invalid: }';
400: } elseif (is_array($body)) {
401: $body = json_encode($body);
402: }
403:
404: $headers['Content-Length'] = strlen($body);
405:
406: return [$status, $headers, $body];
407: }
408:
409: private function makeRequest(
410: $service,
411: $ipAddress,
412: $locales = ['en'],
413: $options = [],
414: $callsToRequest = 1
415: ) {
416: $userId = 42;
417: $licenseKey = 'abcdef123456';
418:
419: list($statusCode, $headers, $responseBody)
420: = $this->getResponse($ipAddress);
421:
422: $stub = $this->getMockForAbstractClass(
423: 'MaxMind\\WebService\\Http\\Request'
424: );
425: $contentType = isset($headers['Content-Type'])
426: ? $headers['Content-Type']
427: : null;
428: $stub->expects($this->exactly($callsToRequest))
429: ->method('get')
430: ->willReturn([$statusCode, $contentType, $responseBody]);
431: $factory = $this->getMockBuilder(
432: 'MaxMind\\WebService\\Http\\RequestFactory'
433: )->getMock();
434: $host = isset($options['host']) ? $options['host'] : 'geoip.maxmind.com';
435: $url = 'https://' . $host . '/geoip/v2.1/' . strtolower($service)
436: . '/' . $ipAddress;
437: $headers = [
438: 'Authorization: Basic '
439: . base64_encode($userId . ':' . $licenseKey),
440: 'Accept: application/json',
441: ];
442:
443: $caBundle = CaBundle::getSystemCaRootBundlePath();
444:
445: $curlVersion = curl_version();
446: $factory->expects($this->exactly($callsToRequest))
447: ->method('request')
448: ->with(
449: $this->equalTo($url),
450: $this->equalTo(
451: [
452: 'headers' => $headers,
453: 'userAgent' => 'GeoIP2-API/' . \GeoIp2\WebService\Client::VERSION
454: . ' MaxMind-WS-API/' . WsClient::VERSION
455: . ' PHP/' . PHP_VERSION
456: . ' curl/' . $curlVersion['version'],
457: 'connectTimeout' => isset($options['connectTimeout'])
458: ? $options['connectTimeout'] : null,
459: 'timeout' => isset($options['timeout'])
460: ? $options['timeout'] : null,
461: 'proxy' => isset($options['proxy'])
462: ? $options['proxy'] : null,
463: 'caBundle' => $caBundle,
464: ]
465: )
466: )->willReturn($stub);
467: $options['httpRequestFactory'] = $factory;
468:
469: $method = strtolower($service);
470:
471: $client = new \GeoIp2\WebService\Client(
472: $userId,
473: $licenseKey,
474: $locales,
475: $options
476: );
477:
478: return $client->$method($ipAddress);
479: }
480: }
481: