├── .gitignore ├── .travis.yml ├── DataCollector └── RequestLogDataCollector.php ├── DependencyInjection ├── Configuration.php └── OdeskPhystrixExtension.php ├── LICENSE ├── OdeskPhystrixBundle.php ├── README.md ├── Resources ├── config │ └── config.yml └── views │ └── Collector │ └── phystrix.html.twig ├── Tests ├── DataCollector │ └── RequestLogDataCollectorTest.php └── DependencyInjection │ └── OdeskPhystrixExtensionTest.php ├── composer.json └── phpunit.xml /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | 3 | composer.lock 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.4 5 | - 5.5 6 | - 5.6 7 | - 7.0 8 | - hhvm 9 | 10 | matrix: 11 | allow_failures: 12 | - php: 7.0 13 | 14 | sudo: false 15 | 16 | before_install: travis_retry composer self-update 17 | 18 | install: travis_retry composer install --no-interaction --prefer-source 19 | 20 | script: phpunit --coverage-text --coverage-clover=coverage.clover Tests/ 21 | 22 | -------------------------------------------------------------------------------- /DataCollector/RequestLogDataCollector.php: -------------------------------------------------------------------------------- 1 | requestLog = $requestLog; 38 | } 39 | 40 | /** 41 | * {@inheritdoc} 42 | */ 43 | public function collect(Request $request, Response $response, \Exception $exception = null) 44 | { 45 | $this->data = array('commands' => array()); 46 | 47 | /** @var AbstractCommand $command */ 48 | foreach ($this->requestLog->getExecutedCommands() as $command) { 49 | $time = $command->getExecutionTimeInMilliseconds(); 50 | if (!$time) { 51 | $time = 0; 52 | } 53 | $this->data['commands'][] = array( 54 | 'class' => get_class($command), 55 | 'duration' => $time, 56 | 'events' => $command->getExecutionEvents(), 57 | ); 58 | } 59 | } 60 | 61 | public function getCommands() 62 | { 63 | return $this->data['commands']; 64 | } 65 | 66 | /** 67 | * {@inheritdoc} 68 | */ 69 | public function getName() 70 | { 71 | return 'phystrix'; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /DependencyInjection/Configuration.php: -------------------------------------------------------------------------------- 1 | root('phystrix'); 34 | 35 | $rootNode 36 | ->useAttributeAsKey('name') 37 | ->prototype('array') 38 | ->children() 39 | ->arrayNode('fallback')->canBeEnabled()->end() 40 | ->arrayNode('circuitBreaker') 41 | ->addDefaultsIfNotSet() 42 | ->canBeEnabled() 43 | ->children() 44 | ->integerNode('errorThresholdPercentage')->defaultValue(50)->end() 45 | ->integerNode('requestVolumeThreshold')->defaultValue(20)->end() 46 | ->integerNode('sleepWindowInMilliseconds')->defaultValue(5000)->end() 47 | ->booleanNode('forceOpen')->defaultValue(false)->end() 48 | ->booleanNode('forceClosed')->defaultValue(false)->end() 49 | ->end() 50 | ->end() 51 | ->arrayNode('metrics') 52 | ->addDefaultsIfNotSet() 53 | ->children() 54 | ->integerNode('healthSnapshotIntervalInMilliseconds')->defaultValue(1000)->end() 55 | ->integerNode('rollingStatisticalWindowInMilliseconds')->defaultValue(1000)->end() 56 | ->integerNode('rollingStatisticalWindowBuckets')->defaultValue(10)->end() 57 | ->end() 58 | ->end() 59 | ->arrayNode('requestCache')->canBeDisabled()->end() 60 | ->arrayNode('requestLog')->canBeEnabled()->end() 61 | ->end() 62 | ->end() 63 | ->validate() 64 | ->ifTrue(function ($data) { 65 | return !array_key_exists('default', $data); 66 | }) 67 | ->thenInvalid("'default' configuration should be set") 68 | ->end(); 69 | 70 | return $treeBuilder; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /DependencyInjection/OdeskPhystrixExtension.php: -------------------------------------------------------------------------------- 1 | processConfiguration($configuration, $configs); 36 | 37 | $loader = new YamlFileLoader( 38 | $container, 39 | new FileLocator(__DIR__.'/../Resources/config') 40 | ); 41 | $loader->load('config.yml'); 42 | 43 | $container->setParameter('phystrix.configuration.data', $config); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Vesion 2.0, Januay 2004 4 | http://www.apache.og/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the tems and conditions fo use, epoduction, 11 | and distibution as defined by Sections 1 though 9 of this document. 12 | 13 | "Licenso" shall mean the copyight owne o entity authoized by 14 | the copyight owne that is ganting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | othe entities that contol, ae contolled by, o ae unde common 18 | contol with that entity. Fo the puposes of this definition, 19 | "contol" means (i) the powe, diect o indiect, to cause the 20 | diection o management of such entity, whethe by contact o 21 | othewise, o (ii) owneship of fifty pecent (50%) o moe of the 22 | outstanding shaes, o (iii) beneficial owneship of such entity. 23 | 24 | "You" (o "You") shall mean an individual o Legal Entity 25 | execising pemissions ganted by this License. 26 | 27 | "Souce" fom shall mean the pefeed fom fo making modifications, 28 | including but not limited to softwae souce code, documentation 29 | souce, and configuation files. 30 | 31 | "Object" fom shall mean any fom esulting fom mechanical 32 | tansfomation o tanslation of a Souce fom, including but 33 | not limited to compiled object code, geneated documentation, 34 | and convesions to othe media types. 35 | 36 | "Wok" shall mean the wok of authoship, whethe in Souce o 37 | Object fom, made available unde the License, as indicated by a 38 | copyight notice that is included in o attached to the wok 39 | (an example is povided in the Appendix below). 40 | 41 | "Deivative Woks" shall mean any wok, whethe in Souce o Object 42 | fom, that is based on (o deived fom) the Wok and fo which the 43 | editoial evisions, annotations, elaboations, o othe modifications 44 | epesent, as a whole, an oiginal wok of authoship. Fo the puposes 45 | of this License, Deivative Woks shall not include woks that emain 46 | sepaable fom, o meely link (o bind by name) to the intefaces of, 47 | the Wok and Deivative Woks theeof. 48 | 49 | "Contibution" shall mean any wok of authoship, including 50 | the oiginal vesion of the Wok and any modifications o additions 51 | to that Wok o Deivative Woks theeof, that is intentionally 52 | submitted to Licenso fo inclusion in the Wok by the copyight owne 53 | o by an individual o Legal Entity authoized to submit on behalf of 54 | the copyight owne. Fo the puposes of this definition, "submitted" 55 | means any fom of electonic, vebal, o witten communication sent 56 | to the Licenso o its epesentatives, including but not limited to 57 | communication on electonic mailing lists, souce code contol systems, 58 | and issue tacking systems that ae managed by, o on behalf of, the 59 | Licenso fo the pupose of discussing and impoving the Wok, but 60 | excluding communication that is conspicuously maked o othewise 61 | designated in witing by the copyight owne as "Not a Contibution." 62 | 63 | "Contibuto" shall mean Licenso and any individual o Legal Entity 64 | on behalf of whom a Contibution has been eceived by Licenso and 65 | subsequently incopoated within the Wok. 66 | 67 | 2. Gant of Copyight License. Subject to the tems and conditions of 68 | this License, each Contibuto heeby gants to You a pepetual, 69 | woldwide, non-exclusive, no-chage, oyalty-fee, ievocable 70 | copyight license to epoduce, pepae Deivative Woks of, 71 | publicly display, publicly pefom, sublicense, and distibute the 72 | Wok and such Deivative Woks in Souce o Object fom. 73 | 74 | 3. Gant of Patent License. Subject to the tems and conditions of 75 | this License, each Contibuto heeby gants to You a pepetual, 76 | woldwide, non-exclusive, no-chage, oyalty-fee, ievocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offe to sell, sell, impot, and othewise tansfe the Wok, 79 | whee such license applies only to those patent claims licensable 80 | by such Contibuto that ae necessaily infinged by thei 81 | Contibution(s) alone o by combination of thei Contibution(s) 82 | with the Wok to which such Contibution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | coss-claim o counteclaim in a lawsuit) alleging that the Wok 85 | o a Contibution incopoated within the Wok constitutes diect 86 | o contibutoy patent infingement, then any patent licenses 87 | ganted to You unde this License fo that Wok shall teminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistibution. You may epoduce and distibute copies of the 91 | Wok o Deivative Woks theeof in any medium, with o without 92 | modifications, and in Souce o Object fom, povided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any othe ecipients of the Wok o 96 | Deivative Woks a copy of this License; and 97 | 98 | (b) You must cause any modified files to cay pominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must etain, in the Souce fom of any Deivative Woks 102 | that You distibute, all copyight, patent, tademak, and 103 | attibution notices fom the Souce fom of the Wok, 104 | excluding those notices that do not petain to any pat of 105 | the Deivative Woks; and 106 | 107 | (d) If the Wok includes a "NOTICE" text file as pat of its 108 | distibution, then any Deivative Woks that You distibute must 109 | include a eadable copy of the attibution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | petain to any pat of the Deivative Woks, in at least one 112 | of the following places: within a NOTICE text file distibuted 113 | as pat of the Deivative Woks; within the Souce fom o 114 | documentation, if povided along with the Deivative Woks; o, 115 | within a display geneated by the Deivative Woks, if and 116 | wheeve such thid-paty notices nomally appea. The contents 117 | of the NOTICE file ae fo infomational puposes only and 118 | do not modify the License. You may add You own attibution 119 | notices within Deivative Woks that You distibute, alongside 120 | o as an addendum to the NOTICE text fom the Wok, povided 121 | that such additional attibution notices cannot be constued 122 | as modifying the License. 123 | 124 | You may add You own copyight statement to You modifications and 125 | may povide additional o diffeent license tems and conditions 126 | fo use, epoduction, o distibution of You modifications, o 127 | fo any such Deivative Woks as a whole, povided You use, 128 | epoduction, and distibution of the Wok othewise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contibutions. Unless You explicitly state othewise, 132 | any Contibution intentionally submitted fo inclusion in the Wok 133 | by You to the Licenso shall be unde the tems and conditions of 134 | this License, without any additional tems o conditions. 135 | Notwithstanding the above, nothing heein shall supesede o modify 136 | the tems of any sepaate license ageement you may have executed 137 | with Licenso egading such Contibutions. 138 | 139 | 6. Tademaks. This License does not gant pemission to use the tade 140 | names, tademaks, sevice maks, o poduct names of the Licenso, 141 | except as equied fo easonable and customay use in descibing the 142 | oigin of the Wok and epoducing the content of the NOTICE file. 143 | 144 | 7. Disclaime of Waanty. Unless equied by applicable law o 145 | ageed to in witing, Licenso povides the Wok (and each 146 | Contibuto povides its Contibutions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, eithe expess o 148 | implied, including, without limitation, any waanties o conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, o FITNESS FOR A 150 | PARTICULAR PURPOSE. You ae solely esponsible fo detemining the 151 | appopiateness of using o edistibuting the Wok and assume any 152 | isks associated with You execise of pemissions unde this License. 153 | 154 | 8. Limitation of Liability. In no event and unde no legal theoy, 155 | whethe in tot (including negligence), contact, o othewise, 156 | unless equied by applicable law (such as delibeate and gossly 157 | negligent acts) o ageed to in witing, shall any Contibuto be 158 | liable to You fo damages, including any diect, indiect, special, 159 | incidental, o consequential damages of any chaacte aising as a 160 | esult of this License o out of the use o inability to use the 161 | Wok (including but not limited to damages fo loss of goodwill, 162 | wok stoppage, compute failue o malfunction, o any and all 163 | othe commecial damages o losses), even if such Contibuto 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Waanty o Additional Liability. While edistibuting 167 | the Wok o Deivative Woks theeof, You may choose to offe, 168 | and chage a fee fo, acceptance of suppot, waanty, indemnity, 169 | o othe liability obligations and/o ights consistent with this 170 | License. Howeve, in accepting such obligations, You may act only 171 | on You own behalf and on You sole esponsibility, not on behalf 172 | of any othe Contibuto, and only if You agee to indemnify, 173 | defend, and hold each Contibuto hamless fo any liability 174 | incued by, o claims asseted against, such Contibuto by eason 175 | of you accepting any such waanty o additional liability. 176 | -------------------------------------------------------------------------------- /OdeskPhystrixBundle.php: -------------------------------------------------------------------------------- 1 | get('phystrix.service_locator')->set('somekey', $somevalue); 81 | ``` 82 | 83 | How to create and run a command: 84 | 85 | ```php 86 | $command = $container->get('phystrix.command_factory')->getCommand('MyCommand', $parameter1, $parameter2); 87 | $command->execute(); 88 | ``` 89 | 90 | ### License 91 | 92 | This file is a part of the Phystrix Bundle 93 | 94 | Copyright 2013-2017 Upwork Global Inc. All Rights Reserved. 95 | 96 | This file is licensed under the Apache License, Version 2.0 (the "License"); 97 | you may not use this file except in compliance with the License. 98 | You may obtain a copy of the License at 99 | 100 | http://www.apache.org/licenses/LICENSE-2.0 101 | 102 | Unless required by applicable law or agreed to in writing, software 103 | distributed under the License is distributed on an "AS IS" BASIS, 104 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 105 | See the License for the specific language governing permissions and 106 | limitations under the License. 107 | -------------------------------------------------------------------------------- /Resources/config/config.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | phystrix.configuration.class: Zend\Config\Config 3 | phystrix.service_locator.class: Zend\Di\ServiceLocator 4 | phystrix.state_storage.class: Odesk\Phystrix\ArrayStateStorage 5 | phystrix.circuit_breaker_factory.class: Odesk\Phystrix\CircuitBreakerFactory 6 | phystrix.command_metrics_factory.class: Odesk\Phystrix\CommandMetricsFactory 7 | phystrix.request_cache.class: Odesk\Phystrix\RequestCache 8 | phystrix.request_log.class: Odesk\Phystrix\RequestLog 9 | phystrix.command_factory.class: Odesk\Phystrix\CommandFactory 10 | 11 | phystrix.data_collector.class: Odesk\Bundle\PhystrixBundle\DataCollector\RequestLogDataCollector 12 | 13 | phystrix.configuration.data: ~ # set by extension 14 | 15 | services: 16 | 17 | phystrix.configuration: 18 | class: %phystrix.configuration.class% 19 | public: false 20 | arguments: 21 | - %phystrix.configuration.data% 22 | 23 | phystrix.service_locator: 24 | class: %phystrix.service_locator.class% 25 | 26 | phystrix.state_storage: 27 | class: %phystrix.state_storage.class% 28 | 29 | phystrix.circuit_breaker_factory: 30 | class: %phystrix.circuit_breaker_factory.class% 31 | arguments: 32 | - "@phystrix.state_storage" 33 | 34 | phystrix.command_metrics_factory: 35 | class: %phystrix.command_metrics_factory.class% 36 | arguments: 37 | - "@phystrix.state_storage" 38 | 39 | phystrix.request_cache: 40 | class: %phystrix.request_cache.class% 41 | 42 | phystrix.request_log: 43 | class: %phystrix.request_log.class% 44 | 45 | phystrix.command_factory: 46 | class: %phystrix.command_factory.class% 47 | arguments: 48 | - "@phystrix.configuration" 49 | - "@phystrix.service_locator" 50 | - "@phystrix.circuit_breaker_factory" 51 | - "@phystrix.command_metrics_factory" 52 | - "@phystrix.request_cache" 53 | - "@phystrix.request_log" 54 | 55 | phystrix.data_collector: 56 | class: %phystrix.data_collector.class% 57 | arguments: 58 | - "@phystrix.request_log" 59 | tags: 60 | - { name: data_collector, template: "OdeskPhystrixBundle:Collector:phystrix", id: "phystrix"} 61 | -------------------------------------------------------------------------------- /Resources/views/Collector/phystrix.html.twig: -------------------------------------------------------------------------------- 1 | {% extends '@WebProfiler/Profiler/layout.html.twig' %} 2 | 3 | {% block toolbar %} 4 | {% set icon %} 5 | 6 | 7 | {% if collector.commands|length %} 8 | {{ collector.commands|length }} Phystrix commands executed 9 | {% else %} 10 | No Phystrix commands executed 11 | {% endif %} 12 | 13 | 14 | {% endset %} 15 | {% include '@WebProfiler/Profiler/toolbar_item.html.twig' with { 'link': profiler_url } %} 16 | {% endblock %} 17 | 18 | {% block menu %} 19 | 20 | Phystrix 21 | 22 | {% endblock %} 23 | 24 | {% block panel %} 25 |

Phystrix commands executed

26 | {% if collector.commands|length %} 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | {% for command in collector.commands %} 37 | 38 | 39 | 40 | 41 | 42 | {% endfor %} 43 | 44 |
CommandDurationEvents
{{ command.class }}{{ command.duration }} ms{{ command.events|join('
') }}
45 | {% else %} 46 |

47 | No Phystrix commands have been executed 48 |

49 | {% endif %} 50 | {% endblock %} 51 | -------------------------------------------------------------------------------- /Tests/DataCollector/RequestLogDataCollectorTest.php: -------------------------------------------------------------------------------- 1 | getMockBuilder('Odesk\Phystrix\RequestLog') 32 | ->disableOriginalConstructor() 33 | ->getMock(); 34 | $requestLogMock->expects($this->once()) 35 | ->method('getExecutedCommands') 36 | ->willReturn(array( 37 | $this->prepareCommandMock('Command1', 234, array('e11', 'e12')), 38 | $this->prepareCommandMock('Command2', 345, array('e2')), 39 | $this->prepareCommandMock('Command3', 456, array('e31', 'e32', 'e33')), 40 | )); 41 | 42 | $collector = new RequestLogDataCollector($requestLogMock); 43 | $collector->collect(new Request(), new Response()); 44 | 45 | $this->assertEquals(array( 46 | array('class' => 'Command1', 'duration' => 234, 'events' => array('e11', 'e12')), 47 | array('class' => 'Command2', 'duration' => 345, 'events' => array('e2')), 48 | array('class' => 'Command3', 'duration' => 456, 'events' => array('e31', 'e32', 'e33')), 49 | ), $collector->getCommands()); 50 | 51 | $this->assertSame('phystrix', $collector->getName()); 52 | } 53 | 54 | /** 55 | * @param string $name 56 | * @param int $executionTime 57 | * @param string[] $executionEvents 58 | * 59 | * @return \PHPUnit_Framework_MockObject_MockObject|\Odesk\Phystrix\AbstractCommand 60 | */ 61 | private function prepareCommandMock($name, $executionTime, $executionEvents) 62 | { 63 | $commandMock = $this->getMockBuilder('\Odesk\Phystrix\AbstractCommand') 64 | ->disableOriginalConstructor() 65 | ->setMockClassName($name) 66 | ->setMethods(array('getExecutionTimeInMilliseconds', 'getExecutionEvents')) 67 | ->getMockForAbstractClass(); 68 | $commandMock->expects($this->once()) 69 | ->method('getExecutionTimeInMilliseconds') 70 | ->willReturn($executionTime); 71 | $commandMock->expects($this->once()) 72 | ->method('getExecutionEvents') 73 | ->willReturn($executionEvents); 74 | 75 | return $commandMock; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Tests/DependencyInjection/OdeskPhystrixExtensionTest.php: -------------------------------------------------------------------------------- 1 | extension = new OdeskPhystrixExtension(); 36 | } 37 | 38 | public function publicServicesNamesProvider() 39 | { 40 | return array( 41 | array('phystrix.command_factory'), 42 | array('phystrix.service_locator'), 43 | ); 44 | } 45 | 46 | /** 47 | * @param string $serviceName 48 | * @dataProvider publicServicesNamesProvider 49 | */ 50 | public function testServiceIsPublic($serviceName) 51 | { 52 | $container = new ContainerBuilder(); 53 | $this->extension->load(array(array('default' => array())), $container); 54 | 55 | $this->assertTrue($container->hasDefinition($serviceName), "Service $serviceName must be defined"); 56 | $definition = $container->getDefinition($serviceName); 57 | $this->assertTrue($definition->isPublic(), "Service $serviceName must be public"); 58 | } 59 | 60 | public function testDefaultConfig() 61 | { 62 | $container = new ContainerBuilder(); 63 | $this->extension->load(array(array('default' => array())), $container); 64 | 65 | $configArrayAll = $container->getParameter('phystrix.configuration.data'); 66 | 67 | $this->assertArrayHasKey('default', $configArrayAll); 68 | 69 | $defaultConfigArray = $configArrayAll['default']; 70 | 71 | // fallback 72 | $this->assertArrayHasKey('fallback', $defaultConfigArray); 73 | $this->assertEquals(false, $defaultConfigArray['fallback']['enabled']); 74 | 75 | // requestCache 76 | $this->assertArrayHasKey('requestCache', $defaultConfigArray); 77 | $this->assertEquals(true, $defaultConfigArray['requestCache']['enabled']); 78 | 79 | // requestLog 80 | $this->assertArrayHasKey('requestLog', $defaultConfigArray); 81 | $this->assertEquals(false, $defaultConfigArray['fallback']['enabled']); 82 | 83 | // circuitBreaker 84 | $this->assertArrayHasKey('circuitBreaker', $defaultConfigArray); 85 | $circuitBreakerConfigArray = $defaultConfigArray['circuitBreaker']; 86 | 87 | $this->assertArrayHasKey('errorThresholdPercentage', $circuitBreakerConfigArray); 88 | $this->assertEquals(50, $circuitBreakerConfigArray['errorThresholdPercentage']); 89 | 90 | $this->assertArrayHasKey('requestVolumeThreshold', $circuitBreakerConfigArray); 91 | $this->assertEquals(20, $circuitBreakerConfigArray['requestVolumeThreshold']); 92 | 93 | $this->assertArrayHasKey('sleepWindowInMilliseconds', $circuitBreakerConfigArray); 94 | $this->assertEquals(5000, $circuitBreakerConfigArray['sleepWindowInMilliseconds']); 95 | 96 | $this->assertArrayHasKey('forceOpen', $circuitBreakerConfigArray); 97 | $this->assertFalse($circuitBreakerConfigArray['forceOpen']); 98 | 99 | $this->assertArrayHasKey('forceClosed', $circuitBreakerConfigArray); 100 | $this->assertFalse($circuitBreakerConfigArray['forceClosed']); 101 | 102 | // metrics 103 | $this->assertArrayHasKey('metrics', $defaultConfigArray); 104 | $metricsConfigArray = $defaultConfigArray['metrics']; 105 | 106 | $this->assertArrayHasKey('healthSnapshotIntervalInMilliseconds', $metricsConfigArray); 107 | $this->assertEquals(1000, $metricsConfigArray['healthSnapshotIntervalInMilliseconds']); 108 | 109 | $this->assertArrayHasKey('rollingStatisticalWindowInMilliseconds', $metricsConfigArray); 110 | $this->assertEquals(1000, $metricsConfigArray['rollingStatisticalWindowInMilliseconds']); 111 | 112 | $this->assertArrayHasKey('rollingStatisticalWindowBuckets', $metricsConfigArray); 113 | $this->assertEquals(10, $metricsConfigArray['rollingStatisticalWindowBuckets']); 114 | } 115 | 116 | public function testChangedConfig() 117 | { 118 | $changedConfig = array( 119 | 'fallback' => true, 120 | 'requestCache' => false, 121 | 'requestLog' => true, 122 | 'circuitBreaker' => array( 123 | 'errorThresholdPercentage' => 101, 124 | 'forceOpen' => true, 125 | 'forceClosed' => true, 126 | 'requestVolumeThreshold' => 102, 127 | 'sleepWindowInMilliseconds' => 103, 128 | ), 129 | 'metrics' => array( 130 | 'healthSnapshotIntervalInMilliseconds' => 104, 131 | 'rollingStatisticalWindowInMilliseconds' => 105, 132 | 'rollingStatisticalWindowBuckets' => 106, 133 | ), 134 | ); 135 | 136 | $container = new ContainerBuilder(); 137 | $this->extension->load(array(array('default' => $changedConfig)), $container); 138 | 139 | $configArrayAll = $container->getParameter('phystrix.configuration.data'); 140 | 141 | $this->assertArrayHasKey('default', $configArrayAll); 142 | 143 | $defaultConfigArray = $configArrayAll['default']; 144 | 145 | // fallback 146 | $this->assertArrayHasKey('fallback', $defaultConfigArray); 147 | $this->assertEquals(true, $defaultConfigArray['fallback']['enabled']); 148 | 149 | // requestCache 150 | $this->assertArrayHasKey('requestCache', $defaultConfigArray); 151 | $this->assertEquals(false, $defaultConfigArray['requestCache']['enabled']); 152 | 153 | // requestLog 154 | $this->assertArrayHasKey('requestLog', $defaultConfigArray); 155 | $this->assertEquals(true, $defaultConfigArray['fallback']['enabled']); 156 | 157 | // circuitBreaker 158 | $this->assertArrayHasKey('circuitBreaker', $defaultConfigArray); 159 | $circuitBreakerConfigArray = $defaultConfigArray['circuitBreaker']; 160 | 161 | $this->assertArrayHasKey('errorThresholdPercentage', $circuitBreakerConfigArray); 162 | $this->assertEquals(101, $circuitBreakerConfigArray['errorThresholdPercentage']); 163 | 164 | $this->assertArrayHasKey('requestVolumeThreshold', $circuitBreakerConfigArray); 165 | $this->assertEquals(102, $circuitBreakerConfigArray['requestVolumeThreshold']); 166 | 167 | $this->assertArrayHasKey('sleepWindowInMilliseconds', $circuitBreakerConfigArray); 168 | $this->assertEquals(103, $circuitBreakerConfigArray['sleepWindowInMilliseconds']); 169 | 170 | $this->assertArrayHasKey('forceOpen', $circuitBreakerConfigArray); 171 | $this->assertTrue($circuitBreakerConfigArray['forceOpen']); 172 | 173 | $this->assertArrayHasKey('forceClosed', $circuitBreakerConfigArray); 174 | $this->assertTrue($circuitBreakerConfigArray['forceClosed']); 175 | 176 | // metrics 177 | $this->assertArrayHasKey('metrics', $defaultConfigArray); 178 | $metricsConfigArray = $defaultConfigArray['metrics']; 179 | 180 | $this->assertArrayHasKey('healthSnapshotIntervalInMilliseconds', $metricsConfigArray); 181 | $this->assertEquals(104, $metricsConfigArray['healthSnapshotIntervalInMilliseconds']); 182 | 183 | $this->assertArrayHasKey('rollingStatisticalWindowInMilliseconds', $metricsConfigArray); 184 | $this->assertEquals(105, $metricsConfigArray['rollingStatisticalWindowInMilliseconds']); 185 | 186 | $this->assertArrayHasKey('rollingStatisticalWindowBuckets', $metricsConfigArray); 187 | $this->assertEquals(106, $metricsConfigArray['rollingStatisticalWindowBuckets']); 188 | } 189 | 190 | /** 191 | * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException 192 | */ 193 | public function testConfigMustHaveDefault() 194 | { 195 | $container = new ContainerBuilder(); 196 | $this->extension->load(array(array()), $container); 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "odesk/phystrix-bundle", 3 | "description": "Phystrix integration with Symfony2 framework.", 4 | "type": "symfony-bundle", 5 | "license": "Apache-2.0", 6 | "keywords": ["odesk", "phystrix", "symfony"], 7 | "autoload": { 8 | "psr-4": { "Odesk\\Bundle\\PhystrixBundle\\": "" } 9 | }, 10 | "require": { 11 | "php": ">=5.3.3", 12 | "odesk/phystrix": "~1.0", 13 | "symfony/http-kernel": "~2.5", 14 | "symfony/dependency-injection": "~2.5", 15 | "symfony/config": "~2.5" 16 | }, 17 | "require-dev": { 18 | "phpunit/phpunit": "~4.2" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ./Tests 5 | 6 | 7 | 8 | 9 | 10 | ./ 11 | 12 | ./Resources 13 | ./Tests 14 | 15 | 16 | 17 | 18 | 19 | --------------------------------------------------------------------------------