Skip to content

Commit ceef56b

Browse files
committed
chore: add test for fix plugin fakeip order
1 parent f4530ab commit ceef56b

6 files changed

+383
-0
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
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

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
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+
* @return array
56+
*/
57+
protected function getKernelParameters()
58+
{
59+
$bundles = [];
60+
$bundlesMetadata = [];
61+
62+
foreach ($this->bundles as $name => $bundle) {
63+
$bundles[$name] = \get_class($bundle);
64+
$bundlesMetadata[$name] = [
65+
'path' => $bundle->getPath(),
66+
'namespace' => $bundle->getNamespace(),
67+
];
68+
}
69+
70+
return [
71+
'kernel.project_dir' => realpath($this->getProjectDir()) ?: $this->getProjectDir(),
72+
'kernel.environment' => $this->environment,
73+
'kernel.runtime_environment' => '%env(default:kernel.environment:APP_RUNTIME_ENV)%',
74+
'kernel.debug' => $this->debug,
75+
'kernel.build_dir' => realpath($buildDir = $this->warmupDir ?: $this->getBuildDir()) ?: $buildDir,
76+
'kernel.cache_dir' => realpath($cacheDir = ($this->getCacheDir() === $this->getBuildDir() ? ($this->warmupDir ?: $this->getCacheDir()) : $this->getCacheDir())) ?: $cacheDir,
77+
'kernel.logs_dir' => realpath($this->getLogDir()) ?: $this->getLogDir(),
78+
'kernel.bundles' => $bundles,
79+
'kernel.bundles_metadata' => $bundlesMetadata,
80+
'kernel.charset' => $this->getCharset(),
81+
'kernel.container_class' => $this->getContainerClass(),
82+
];
83+
}
84+
85+
/**
86+
* @internal
87+
*/
88+
public function setAnnotatedClassCache(array $annotatedClasses)
89+
{
90+
file_put_contents(($this->warmupDir ?: $this->getBuildDir()).'/annotations.map', sprintf('<?php return %s;', var_export($annotatedClasses, true)));
91+
}
92+
93+
/**
94+
* Initializes the service container.
95+
*
96+
* The built version of the service container is used when fresh, otherwise the
97+
* container is built.
98+
*/
99+
protected function initializeContainer()
100+
{
101+
$class = $this->getContainerClass();
102+
$buildDir = $this->warmupDir ?: $this->getBuildDir();
103+
$cache = new ConfigCache($buildDir.'/'.$class.'.php', $this->debug);
104+
$cachePath = $cache->getPath();
105+
106+
// Silence E_WARNING to ignore "include" failures - don't use "@" to prevent silencing fatal errors
107+
$errorLevel = error_reporting(\E_ALL ^ \E_WARNING);
108+
109+
try {
110+
if (false && \is_object($this->container = include $cachePath)
111+
&& (!$this->debug || (self::$freshCache[$cachePath] ?? $cache->isFresh()))
112+
) {
113+
self::$freshCache[$cachePath] = true;
114+
$this->container->set('kernel', $this);
115+
error_reporting($errorLevel);
116+
117+
return;
118+
}
119+
} catch (\Throwable $e) {
120+
}
121+
122+
$oldContainer = \is_object($this->container) ? new \ReflectionClass($this->container) : $this->container = null;
123+
124+
try {
125+
is_dir($buildDir) ?: mkdir($buildDir, 0777, true);
126+
127+
if ($lock = fopen($cachePath.'.lock', 'w')) {
128+
if (!flock($lock, \LOCK_EX | \LOCK_NB, $wouldBlock) && !flock($lock, $wouldBlock ? \LOCK_SH : \LOCK_EX)) {
129+
fclose($lock);
130+
$lock = null;
131+
} elseif (true || !\is_object($this->container = include $cachePath)) {
132+
$this->container = null;
133+
} elseif (!$oldContainer || \get_class($this->container) !== $oldContainer->name) {
134+
flock($lock, \LOCK_UN);
135+
fclose($lock);
136+
$this->container->set('kernel', $this);
137+
138+
return;
139+
}
140+
}
141+
} catch (\Throwable $e) {
142+
} finally {
143+
error_reporting($errorLevel);
144+
}
145+
146+
if ($collectDeprecations = $this->debug && !\defined('PHPUNIT_COMPOSER_INSTALL')) {
147+
$collectedLogs = [];
148+
$previousHandler = set_error_handler(function ($type, $message, $file, $line) use (&$collectedLogs, &$previousHandler) {
149+
if (\E_USER_DEPRECATED !== $type && \E_DEPRECATED !== $type) {
150+
return $previousHandler ? $previousHandler($type, $message, $file, $line) : false;
151+
}
152+
153+
if (isset($collectedLogs[$message])) {
154+
++$collectedLogs[$message]['count'];
155+
156+
return null;
157+
}
158+
159+
$backtrace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 5);
160+
// Clean the trace by removing first frames added by the error handler itself.
161+
for ($i = 0; isset($backtrace[$i]); ++$i) {
162+
if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) {
163+
$backtrace = \array_slice($backtrace, 1 + $i);
164+
break;
165+
}
166+
}
167+
for ($i = 0; isset($backtrace[$i]); ++$i) {
168+
if (!isset($backtrace[$i]['file'], $backtrace[$i]['line'], $backtrace[$i]['function'])) {
169+
continue;
170+
}
171+
if (!isset($backtrace[$i]['class']) && 'trigger_deprecation' === $backtrace[$i]['function']) {
172+
$file = $backtrace[$i]['file'];
173+
$line = $backtrace[$i]['line'];
174+
$backtrace = \array_slice($backtrace, 1 + $i);
175+
break;
176+
}
177+
}
178+
179+
// Remove frames added by DebugClassLoader.
180+
for ($i = \count($backtrace) - 2; 0 < $i; --$i) {
181+
if (\in_array($backtrace[$i]['class'] ?? null, [DebugClassLoader::class, LegacyDebugClassLoader::class], true)) {
182+
$backtrace = [$backtrace[$i + 1]];
183+
break;
184+
}
185+
}
186+
187+
$collectedLogs[$message] = [
188+
'type' => $type,
189+
'message' => $message,
190+
'file' => $file,
191+
'line' => $line,
192+
'trace' => [$backtrace[0]],
193+
'count' => 1,
194+
];
195+
196+
return null;
197+
});
198+
}
199+
200+
try {
201+
$container = null;
202+
$container = $this->buildContainer();
203+
$container->compile();
204+
} finally {
205+
if ($collectDeprecations) {
206+
restore_error_handler();
207+
208+
@file_put_contents($buildDir.'/'.$class.'Deprecations.log', serialize(array_values($collectedLogs)));
209+
@file_put_contents($buildDir.'/'.$class.'Compiler.log', null !== $container ? implode("\n", $container->getCompiler()->getLog()) : '');
210+
}
211+
}
212+
213+
$this->dumpContainer($cache, $container, $class, $this->getContainerBaseClass());
214+
215+
if ($lock) {
216+
flock($lock, \LOCK_UN);
217+
fclose($lock);
218+
}
219+
220+
$this->container = require $cachePath;
221+
$this->container->set('kernel', $this);
222+
223+
if ($oldContainer && \get_class($this->container) !== $oldContainer->name) {
224+
// Because concurrent requests might still be using them,
225+
// old container files are not removed immediately,
226+
// but on a next dump of the container.
227+
static $legacyContainers = [];
228+
$oldContainerDir = \dirname($oldContainer->getFileName());
229+
$legacyContainers[$oldContainerDir.'.legacy'] = true;
230+
foreach (glob(\dirname($oldContainerDir).\DIRECTORY_SEPARATOR.'*.legacy', \GLOB_NOSORT) as $legacyContainer) {
231+
if (!isset($legacyContainers[$legacyContainer]) && @unlink($legacyContainer)) {
232+
(new Filesystem())->remove(substr($legacyContainer, 0, -7));
233+
}
234+
}
235+
236+
touch($oldContainerDir.'.legacy');
237+
}
238+
239+
$preload = $this instanceof WarmableInterface ? (array) $this->warmUp($this->container->getParameter('kernel.cache_dir')) : [];
240+
241+
if ($this->container->has('cache_warmer')) {
242+
$preload = array_merge($preload, (array) $this->container->get('cache_warmer')->warmUp($this->container->getParameter('kernel.cache_dir')));
243+
}
244+
245+
if ($preload && method_exists(Preloader::class, 'append') && file_exists($preloadFile = $buildDir.'/'.$class.'.preload.php')) {
246+
Preloader::append($preloadFile, $preload);
247+
}
248+
}
249+
}
Lines changed: 76 additions & 0 deletions
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+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
framework:
2+
cache:
3+
# Put the unique name of your app here: the prefix seed
4+
# is used to compute stable namespaces for cache keys.
5+
#prefix_seed: your_vendor_name/app_name
6+
7+
# The app cache caches to the filesystem by default.
8+
# Other options include:
9+
10+
# Redis
11+
#app: cache.adapter.redis
12+
#default_redis_provider: redis://localhost
13+
14+
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
15+
#app: cache.adapter.apcu
16+
17+
# Namespaced pools use the above "app" backend by default
18+
#pools:
19+
#my.dedicated.cache: ~
20+
app: cache.adapter.filesystem
21+
system: cache.adapter.system
22+
pools:
23+
app.cache.geoPlugin:
24+
adapter: cache.app
25+
default_lifetime: 600
26+
services:
27+
app.simple_cache:
28+
class: Symfony\Component\Cache\Psr16Cache
29+
arguments: ['@app.cache.geoPlugin']
Lines changed: 14 additions & 0 deletions
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: ~
Lines changed: 14 additions & 0 deletions
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)