Skip to content

Commit 646de1a

Browse files
authored
implement query activator (#13)
* implement query activator * update readme
1 parent 67e2466 commit 646de1a

File tree

9 files changed

+125
-9
lines changed

9 files changed

+125
-9
lines changed

README.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ Chaos Monkey for Symfony applications. Try to attack your running Symfony App.
2121
- Repository (not implemented)
2222
- Service (not implemented)
2323

24+
## Activators
25+
26+
- "Query param" - attack only if given query param is present (default `chaos`)
27+
2428
## Symfony
2529

2630
## How to use
@@ -62,10 +66,12 @@ chaos_monkey:
6266
request:
6367
enabled: true
6468
priority: 0
69+
activators:
70+
query_param: false # if true then chaos monkey will be called only if given query param exist (with any value)
71+
query_param_name: 'chaos'
6572
```
6673

6774
## Roadmap
68-
- [ ] Query param activator
6975
- [ ] Flex recipe
7076
- [ ] Metrics (for example `chaos_monkey_request_count_assaulted`)
7177
- [ ] Assault profiles - each profile can contain different assaults

src/Activator/QueryParamActivator.php

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Chaos\Monkey\Symfony\Activator;
6+
7+
use Symfony\Component\HttpFoundation\Request;
8+
9+
final class QueryParamActivator
10+
{
11+
public function __construct(private readonly bool $enabled = false, private readonly string $paramName = 'chaos')
12+
{
13+
}
14+
15+
public function inChaos(Request $request): bool
16+
{
17+
if (!$this->enabled) {
18+
return true;
19+
}
20+
21+
return $request->query->has($this->paramName);
22+
}
23+
}

src/DependencyInjection/ChaosMonkeyExtension.php

+17
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
* },
2222
* watchers: array{
2323
* request: array{enabled: bool, priority: int}
24+
* },
25+
* activators: array{
26+
* query_param: bool,
27+
* query_param_name: string
2428
* }
2529
* }
2630
*/
@@ -39,6 +43,7 @@ public function load(array $configs, ContainerBuilder $container): void
3943
$config = $this->processConfiguration($configuration, $configs);
4044

4145
$this->setChaosMonkeySettings($container, $config);
46+
$this->setActivators($container, $config);
4247
$this->enableWatchers($container, $config);
4348
}
4449

@@ -77,4 +82,16 @@ private function enableWatchers(ContainerBuilder $container, array $config): voi
7782
]);
7883
}
7984
}
85+
86+
/**
87+
* @param ConfigArray $config
88+
*/
89+
private function setActivators(ContainerBuilder $container, array $config): void
90+
{
91+
$queryParam = $container->getDefinition('chaos_monkey.activator.query_param');
92+
$queryParam->setArguments([
93+
'$enabled' => $config['activators']['query_param'],
94+
'$paramName' => $config['activators']['query_param_name'],
95+
]);
96+
}
8097
}

src/DependencyInjection/Configuration.php

+7
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@ public function getConfigTreeBuilder(): TreeBuilder
6565
->end()
6666
->end()
6767
->end()
68+
->arrayNode('activators')
69+
->addDefaultsIfNotSet()
70+
->children()
71+
->booleanNode('query_param')->defaultFalse()->end()
72+
->scalarNode('query_param_name')->defaultValue('chaos')->end()
73+
->end()
74+
->end()
6875
->end();
6976

7077
return $treeBuilder;

src/Resources/config/services.xml

+4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414

1515
<service id="chaos_monkey.watcher.request" class="Chaos\Monkey\Symfony\Watcher\RequestWatcher" public="false">
1616
<argument type="service" id="chaos_monkey" />
17+
<argument type="service" id="chaos_monkey.activator.query_param" />
18+
</service>
19+
20+
<service id="chaos_monkey.activator.query_param" class="Chaos\Monkey\Symfony\Activator\QueryParamActivator" public="false">
1721
</service>
1822

1923
<instanceof id="Chaos\Monkey\Assault" autowire="true">

src/Watcher/RequestWatcher.php

+9-7
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55
namespace Chaos\Monkey\Symfony\Watcher;
66

77
use Chaos\Monkey\ChaosMonkey;
8+
use Chaos\Monkey\Symfony\Activator\QueryParamActivator;
89
use Symfony\Component\HttpKernel\Event\RequestEvent;
910

10-
class RequestWatcher
11+
final class RequestWatcher
1112
{
12-
private ChaosMonkey $chaosMonkey;
13-
14-
public function __construct(ChaosMonkey $chaosMonkey)
15-
{
16-
$this->chaosMonkey = $chaosMonkey;
13+
public function __construct(
14+
private readonly ChaosMonkey $chaosMonkey,
15+
private readonly QueryParamActivator $queryParamActivator
16+
) {
1717
}
1818

1919
public function onKernelRequest(RequestEvent $event): void
@@ -22,6 +22,8 @@ public function onKernelRequest(RequestEvent $event): void
2222
return;
2323
}
2424

25-
$this->chaosMonkey->call();
25+
if ($this->queryParamActivator->inChaos($event->getRequest())) {
26+
$this->chaosMonkey->call();
27+
}
2628
}
2729
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Chaos\Monkey\Symfony\Tests\Activator;
6+
7+
use Chaos\Monkey\Symfony\Activator\QueryParamActivator;
8+
use PHPUnit\Framework\TestCase;
9+
use Symfony\Component\HttpFoundation\Request;
10+
11+
final class QueryParamActivatorTest extends TestCase
12+
{
13+
public function testItIsInChaosIfDisabled(): void
14+
{
15+
$activator = new QueryParamActivator();
16+
17+
self::assertTrue($activator->inChaos(new Request()));
18+
}
19+
20+
public function testItIsNoInChaosIfEnabledAndParamMissing(): void
21+
{
22+
$activator = new QueryParamActivator(true);
23+
24+
self::assertFalse($activator->inChaos(new Request()));
25+
}
26+
27+
public function testItIsInChaosIfEnabledAndParamExists(): void
28+
{
29+
$activator = new QueryParamActivator(true, 'bye');
30+
31+
self::assertTrue($activator->inChaos(new Request(['bye' => true])));
32+
}
33+
}

tests/Controller/SymfonyControllerTest.php

+24-1
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
namespace Chaos\Monkey\Symfony\Tests\Controller;
66

77
use Chaos\Monkey\Settings;
8+
use Chaos\Monkey\Symfony\Activator\QueryParamActivator;
89
use Chaos\Monkey\Symfony\Tests\Symfony\Kernel;
910
use PHPUnit\Framework\TestCase;
1011
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
12+
use Symfony\Component\HttpKernel\Exception\LockedHttpException;
1113
use Symfony\Component\Stopwatch\Stopwatch;
1214

1315
class SymfonyControllerTest extends TestCase
@@ -49,7 +51,22 @@ public function testRequestExceptionAttack(): void
4951
$this->enableExceptionAssault();
5052
$this->client->request('GET', '/hello');
5153

52-
self::assertEquals(500, $this->client->getResponse()->getStatusCode());
54+
self::assertEquals(423, $this->client->getResponse()->getStatusCode());
55+
56+
$this->disableExceptionAssault();
57+
}
58+
59+
public function testRequestExceptionAttackWithQueryParamActivatorEnabled(): void
60+
{
61+
$this->enableQueryParamActivator();
62+
$this->enableExceptionAssault();
63+
$this->client->request('GET', '/hello');
64+
65+
self::assertEquals(200, $this->client->getResponse()->getStatusCode());
66+
67+
$this->client->request('GET', '/hello?chaos=true');
68+
69+
self::assertEquals(423, $this->client->getResponse()->getStatusCode());
5370

5471
$this->disableExceptionAssault();
5572
}
@@ -58,6 +75,7 @@ private function enableExceptionAssault(): void
5875
{
5976
$this->chaosMonkeySettings()->setEnabled(true);
6077
$this->chaosMonkeySettings()->setExceptionActive(true);
78+
$this->chaosMonkeySettings()->setExceptionClass(LockedHttpException::class);
6179
$this->chaosMonkeySettings()->setProbability(100);
6280
}
6381

@@ -84,4 +102,9 @@ private function chaosMonkeySettings(): Settings
84102
{
85103
return $this->client->getContainer()->get('chaos_monkey')->settings();
86104
}
105+
106+
private function enableQueryParamActivator(): void
107+
{
108+
$this->client->getContainer()->get('test.service_container')->set('chaos_monkey.activator.query_param', new QueryParamActivator(true));
109+
}
87110
}

tests/Symfony/Kernel.php

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ protected function configureContainer(ContainerConfigurator $container): void
2929
{
3030
$container->extension('framework', [
3131
'secret' => 'S0ME_SECRET',
32+
'test' => true,
3233
]);
3334

3435
$container->services()->set('logger', NullLogger::class);

0 commit comments

Comments
 (0)