Skip to content

Commit b697587

Browse files
authored
Merge pull request #338 from ruano-a/fix/plugin-fakeip-order-test
Add test for fix plugin fakeip order
2 parents f4530ab + 497b68f commit b697587

6 files changed

+364
-0
lines changed

composer.json

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
"php-http/curl-client": "^2.2",
6060
"php-http/message": "^1.13",
6161
"phpstan/phpstan": "^1.9.2",
62+
"symfony/cache": "^4.4 || ^5.0 || ^6.0",
6263
"symfony/config": "^4.4 || ^5.0 || ^6.0",
6364
"symfony/phpunit-bridge": "^5.2 || ^6.0",
6465
"symfony/validator": "^4.4 || ^5.0 || ^6.0",

tests/Functional/CustomTestKernel.php

+247
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the BazingaGeocoderBundle package.
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*
10+
* @license MIT License
11+
*/
12+
13+
namespace Bazinga\GeocoderBundle\Tests\Functional;
14+
15+
use Nyholm\BundleTest\TestKernel;
16+
use Symfony\Component\Config\ConfigCache;
17+
use Symfony\Component\Debug\DebugClassLoader as LegacyDebugClassLoader;
18+
use Symfony\Component\DependencyInjection\Dumper\Preloader;
19+
use Symfony\Component\ErrorHandler\DebugClassLoader;
20+
use Symfony\Component\Filesystem\Filesystem;
21+
22+
/*
23+
* Needed by PluginInteractionTest, so the test uses the cache for geoCoder, and doesn't clear it each time
24+
* BUT doesn't use the cache for the service parameters, like it is happening in dev
25+
*
26+
* warmupDir is redefined because the method initializeContainer() is using it, but it's private in the parent.
27+
* the methods using it (reboot() and getKernelParameters() and setAnnotatedClassCache() ) therefore needed to be redeclared, in order
28+
* for them to have a correct value in it.
29+
*/
30+
class CustomTestKernel extends TestKernel
31+
{
32+
private $warmupDir;
33+
34+
/**
35+
* {@inheritdoc}
36+
*/
37+
public function reboot(?string $warmupDir)
38+
{
39+
$this->shutdown();
40+
$this->warmupDir = $warmupDir;
41+
$this->boot();
42+
}
43+
44+
/*
45+
* Needed, otherwise the used cache is different on each kernel boot, which is a big issue in PluginInteractionTest
46+
*/
47+
public function getCacheDir(): string
48+
{
49+
return realpath(sys_get_temp_dir()).'/NyholmBundleTest/cachePluginInteractionTest';
50+
}
51+
52+
/**
53+
* Returns the kernel parameters.
54+
*/
55+
protected function getKernelParameters(): array
56+
{
57+
$bundles = [];
58+
$bundlesMetadata = [];
59+
60+
foreach ($this->bundles as $name => $bundle) {
61+
$bundles[$name] = \get_class($bundle);
62+
$bundlesMetadata[$name] = [
63+
'path' => $bundle->getPath(),
64+
'namespace' => $bundle->getNamespace(),
65+
];
66+
}
67+
68+
return [
69+
'kernel.project_dir' => realpath($this->getProjectDir()) ?: $this->getProjectDir(),
70+
'kernel.environment' => $this->environment,
71+
'kernel.runtime_environment' => '%env(default:kernel.environment:APP_RUNTIME_ENV)%',
72+
'kernel.debug' => $this->debug,
73+
'kernel.build_dir' => realpath($buildDir = $this->warmupDir ?: $this->getBuildDir()) ?: $buildDir,
74+
'kernel.cache_dir' => realpath($cacheDir = ($this->getCacheDir() === $this->getBuildDir() ? ($this->warmupDir ?: $this->getCacheDir()) : $this->getCacheDir())) ?: $cacheDir,
75+
'kernel.logs_dir' => realpath($this->getLogDir()) ?: $this->getLogDir(),
76+
'kernel.bundles' => $bundles,
77+
'kernel.bundles_metadata' => $bundlesMetadata,
78+
'kernel.charset' => $this->getCharset(),
79+
'kernel.container_class' => $this->getContainerClass(),
80+
];
81+
}
82+
83+
/**
84+
* @internal
85+
*/
86+
public function setAnnotatedClassCache(array $annotatedClasses)
87+
{
88+
file_put_contents(($this->warmupDir ?: $this->getBuildDir()).'/annotations.map', sprintf('<?php return %s;', var_export($annotatedClasses, true)));
89+
}
90+
91+
/**
92+
* Initializes the service container.
93+
*
94+
* The built version of the service container is used when fresh, otherwise the
95+
* container is built.
96+
*/
97+
protected function initializeContainer()
98+
{
99+
$class = $this->getContainerClass();
100+
$buildDir = $this->warmupDir ?: $this->getBuildDir();
101+
$cache = new ConfigCache($buildDir.'/'.$class.'.php', $this->debug);
102+
$cachePath = $cache->getPath();
103+
104+
// Silence E_WARNING to ignore "include" failures - don't use "@" to prevent silencing fatal errors
105+
$errorLevel = error_reporting(\E_ALL ^ \E_WARNING);
106+
107+
try {
108+
if (false && \is_object($this->container = include $cachePath)
109+
&& (!$this->debug || (self::$freshCache[$cachePath] ?? $cache->isFresh()))
110+
) {
111+
self::$freshCache[$cachePath] = true;
112+
$this->container->set('kernel', $this);
113+
error_reporting($errorLevel);
114+
115+
return;
116+
}
117+
} catch (\Throwable $e) {
118+
}
119+
120+
$oldContainer = \is_object($this->container) ? new \ReflectionClass($this->container) : $this->container = null;
121+
122+
try {
123+
is_dir($buildDir) ?: mkdir($buildDir, 0777, true);
124+
125+
if ($lock = fopen($cachePath.'.lock', 'w')) {
126+
if (!flock($lock, \LOCK_EX | \LOCK_NB, $wouldBlock) && !flock($lock, $wouldBlock ? \LOCK_SH : \LOCK_EX)) {
127+
fclose($lock);
128+
$lock = null;
129+
} elseif (true || !\is_object($this->container = include $cachePath)) {
130+
$this->container = null;
131+
} elseif (!$oldContainer || \get_class($this->container) !== $oldContainer->name) {
132+
flock($lock, \LOCK_UN);
133+
fclose($lock);
134+
$this->container->set('kernel', $this);
135+
136+
return;
137+
}
138+
}
139+
} catch (\Throwable $e) {
140+
} finally {
141+
error_reporting($errorLevel);
142+
}
143+
144+
if ($collectDeprecations = $this->debug && !\defined('PHPUNIT_COMPOSER_INSTALL')) {
145+
$collectedLogs = [];
146+
$previousHandler = set_error_handler(function ($type, $message, $file, $line) use (&$collectedLogs, &$previousHandler) {
147+
if (\E_USER_DEPRECATED !== $type && \E_DEPRECATED !== $type) {
148+
return $previousHandler ? $previousHandler($type, $message, $file, $line) : false;
149+
}
150+
151+
if (isset($collectedLogs[$message])) {
152+
++$collectedLogs[$message]['count'];
153+
154+
return null;
155+
}
156+
157+
$backtrace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 5);
158+
// Clean the trace by removing first frames added by the error handler itself.
159+
for ($i = 0; isset($backtrace[$i]); ++$i) {
160+
if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) {
161+
$backtrace = \array_slice($backtrace, 1 + $i);
162+
break;
163+
}
164+
}
165+
for ($i = 0; isset($backtrace[$i]); ++$i) {
166+
if (!isset($backtrace[$i]['file'], $backtrace[$i]['line'], $backtrace[$i]['function'])) {
167+
continue;
168+
}
169+
if (!isset($backtrace[$i]['class']) && 'trigger_deprecation' === $backtrace[$i]['function']) {
170+
$file = $backtrace[$i]['file'];
171+
$line = $backtrace[$i]['line'];
172+
$backtrace = \array_slice($backtrace, 1 + $i);
173+
break;
174+
}
175+
}
176+
177+
// Remove frames added by DebugClassLoader.
178+
for ($i = \count($backtrace) - 2; 0 < $i; --$i) {
179+
if (\in_array($backtrace[$i]['class'] ?? null, [DebugClassLoader::class, LegacyDebugClassLoader::class], true)) {
180+
$backtrace = [$backtrace[$i + 1]];
181+
break;
182+
}
183+
}
184+
185+
$collectedLogs[$message] = [
186+
'type' => $type,
187+
'message' => $message,
188+
'file' => $file,
189+
'line' => $line,
190+
'trace' => [$backtrace[0]],
191+
'count' => 1,
192+
];
193+
194+
return null;
195+
});
196+
}
197+
198+
try {
199+
$container = null;
200+
$container = $this->buildContainer();
201+
$container->compile();
202+
} finally {
203+
if ($collectDeprecations) {
204+
restore_error_handler();
205+
206+
@file_put_contents($buildDir.'/'.$class.'Deprecations.log', serialize(array_values($collectedLogs)));
207+
@file_put_contents($buildDir.'/'.$class.'Compiler.log', null !== $container ? implode("\n", $container->getCompiler()->getLog()) : '');
208+
}
209+
}
210+
211+
$this->dumpContainer($cache, $container, $class, $this->getContainerBaseClass());
212+
213+
if ($lock) {
214+
flock($lock, \LOCK_UN);
215+
fclose($lock);
216+
}
217+
218+
$this->container = require $cachePath;
219+
$this->container->set('kernel', $this);
220+
221+
if ($oldContainer && \get_class($this->container) !== $oldContainer->name) {
222+
// Because concurrent requests might still be using them,
223+
// old container files are not removed immediately,
224+
// but on a next dump of the container.
225+
static $legacyContainers = [];
226+
$oldContainerDir = \dirname($oldContainer->getFileName());
227+
$legacyContainers[$oldContainerDir.'.legacy'] = true;
228+
foreach (glob(\dirname($oldContainerDir).\DIRECTORY_SEPARATOR.'*.legacy', \GLOB_NOSORT) as $legacyContainer) {
229+
if (!isset($legacyContainers[$legacyContainer]) && @unlink($legacyContainer)) {
230+
(new Filesystem())->remove(substr($legacyContainer, 0, -7));
231+
}
232+
}
233+
234+
touch($oldContainerDir.'.legacy');
235+
}
236+
237+
$preload = $this instanceof WarmableInterface ? (array) $this->warmUp($this->container->getParameter('kernel.cache_dir')) : [];
238+
239+
if ($this->container->has('cache_warmer')) {
240+
$preload = array_merge($preload, (array) $this->container->get('cache_warmer')->warmUp($this->container->getParameter('kernel.cache_dir')));
241+
}
242+
243+
if ($preload && method_exists(Preloader::class, 'append') && file_exists($preloadFile = $buildDir.'/'.$class.'.preload.php')) {
244+
Preloader::append($preloadFile, $preload);
245+
}
246+
}
247+
}
+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the BazingaGeocoderBundle package.
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*
10+
* @license MIT License
11+
*/
12+
13+
namespace Bazinga\GeocoderBundle\Tests\Functional;
14+
15+
use Bazinga\GeocoderBundle\BazingaGeocoderBundle;
16+
use Bazinga\GeocoderBundle\Tests\PublicServicePass;
17+
use Geocoder\Query\GeocodeQuery;
18+
use Nyholm\BundleTest\TestKernel;
19+
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
20+
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
21+
use Symfony\Component\HttpKernel\KernelInterface;
22+
23+
final class PluginInteractionTest extends KernelTestCase
24+
{
25+
use ExpectDeprecationTrait;
26+
27+
protected static function getKernelClass(): string
28+
{
29+
return CustomTestKernel::class;
30+
}
31+
32+
protected static function createKernel(array $options = []): KernelInterface
33+
{
34+
/**
35+
* @var TestKernel $kernel
36+
*/
37+
$kernel = parent::createKernel($options);
38+
$kernel->addTestBundle(BazingaGeocoderBundle::class);
39+
$kernel->addTestCompilerPass(new PublicServicePass('|[Bb]azinga:*|'));
40+
$kernel->addTestCompilerPass(new PublicServicePass('|[gG]eocoder:*|'));
41+
$kernel->handleOptions($options);
42+
43+
return $kernel;
44+
}
45+
46+
public function testCachePluginUsesIpFromFakeIpPlugin(): void
47+
{
48+
$kernel = self::bootKernel(['config' => static function (TestKernel $kernel) {
49+
$kernel->setClearCacheAfterShutdown(false);
50+
$kernel->addTestConfig(__DIR__.'/config/framework.yml');
51+
$kernel->addTestConfig(__DIR__.'/config/cache_symfony.yml');
52+
$kernel->addTestConfig(__DIR__.'/config/geo_plugin_fakeip_with_cache_cn.yml');
53+
}]);
54+
$kernel->setClearCacheAfterShutdown(false);
55+
$container = method_exists(__CLASS__, 'getContainer') ? self::getContainer() : $kernel->getContainer();
56+
57+
$geoPluginGeocoder = $container->get('bazinga_geocoder.provider.geoPlugin');
58+
$result = $geoPluginGeocoder->geocodeQuery(GeocodeQuery::create('::1'));
59+
$country = $result->first()->getCountry()->getCode();
60+
self::assertEquals('CN', $country);
61+
62+
$kernel = self::bootKernel(['config' => static function (TestKernel $kernel) {
63+
$kernel->setClearCacheAfterShutdown(false);
64+
$kernel->addTestConfig(__DIR__.'/config/framework.yml');
65+
$kernel->addTestConfig(__DIR__.'/config/cache_symfony.yml');
66+
$kernel->addTestConfig(__DIR__.'/config/geo_plugin_fakeip_with_cache_fr.yml');
67+
}]);
68+
$kernel->setClearCacheAfterShutdown(false);
69+
$container = method_exists(__CLASS__, 'getContainer') ? self::getContainer() : $kernel->getContainer();
70+
71+
$geoPluginGeocoder = $container->get('bazinga_geocoder.provider.geoPlugin');
72+
$result = $geoPluginGeocoder->geocodeQuery(GeocodeQuery::create('::1'));
73+
$country = $result->first()->getCountry()->getCode();
74+
self::assertEquals('FR', $country);
75+
}
76+
}
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
framework:
2+
cache:
3+
app: cache.adapter.filesystem
4+
system: cache.adapter.system
5+
pools:
6+
app.cache.geoPlugin:
7+
adapter: cache.app
8+
default_lifetime: 600
9+
services:
10+
app.simple_cache:
11+
class: Symfony\Component\Cache\Psr16Cache
12+
arguments: ['@app.cache.geoPlugin']
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# See the docs at https://github.com/geocoder-php/BazingaGeocoderBundle
2+
bazinga_geocoder:
3+
# The local IP (127.0.0.1) will be replaced by the fake_ip
4+
# see https://github.com/geocoder-php/BazingaGeocoderBundle/blob/5.0.0/Resources/doc/index.md#fake-local-ip
5+
fake_ip:
6+
local_ip: ::1
7+
ip: 123.123.123.128
8+
# this ip is in china
9+
providers:
10+
geoPlugin:
11+
factory: Bazinga\GeocoderBundle\ProviderFactory\GeoPluginFactory
12+
cache: 'app.simple_cache'
13+
cache_lifetime: 42
14+
cache_precision: ~
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# See the docs at https://github.com/geocoder-php/BazingaGeocoderBundle
2+
bazinga_geocoder:
3+
# The local IP (127.0.0.1) will be replaced by the fake_ip
4+
# see https://github.com/geocoder-php/BazingaGeocoderBundle/blob/5.0.0/Resources/doc/index.md#fake-local-ip
5+
fake_ip:
6+
local_ip: ::1
7+
ip: 87.98.128.10
8+
# this ip is in france
9+
providers:
10+
geoPlugin:
11+
factory: Bazinga\GeocoderBundle\ProviderFactory\GeoPluginFactory
12+
cache: 'app.simple_cache'
13+
cache_lifetime: 42
14+
cache_precision: ~

0 commit comments

Comments
 (0)