Skip to content

Commit 0ccd131

Browse files
committed
Provide test functionality in traits
Fix #202. separate http client from trait Make property and methods private Add traits to docs
1 parent bb3ff1d commit 0ccd131

14 files changed

+930
-629
lines changed

doc/includes/symfony-process.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Requires Symfony’s Process component, so make sure to include that in your
2+
project:
3+
4+
.. code-block:: bash
5+
6+
$ composer require symfony/process

doc/proxy-clients.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ Then pass that adapter to the caching proxy client::
6666
$proxyClient = new Varnish($servers, '/baseUrl', $adapter);
6767
// Varnish as example, but also possible for NGINX and Symfony
6868

69+
.. _varnish client:
70+
6971
Varnish Client
7072
~~~~~~~~~~~~~~
7173

doc/symfony-cache-configuration.rst

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,4 +179,34 @@ the ``session_name_prefix`` option) in the requests to the backend. If you need
179179
a different behavior, overwrite ``UserContextSubscriber::cleanupHashLookupRequest``
180180
with your own logic.
181181

182+
.. _symfony-cache x-debugging:
183+
184+
Debugging
185+
~~~~~~~~~
186+
187+
For the ``assertHit`` and ``assertMiss`` assertions to work, you need to add
188+
debug information in your AppCache. Create the cache kernel with the option
189+
``'debug' => true`` and add the following to your ``AppCache``::
190+
191+
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
192+
{
193+
$response = parent::handle($request, $type, $catch);
194+
195+
if ($response->headers->has('X-Symfony-Cache')) {
196+
if (false !== strpos($response->headers->get('X-Symfony-Cache'), 'miss')) {
197+
$state = 'MISS';
198+
} elseif (false !== strpos($response->headers->get('X-Symfony-Cache'), 'fresh')) {
199+
$state = 'HIT';
200+
} else {
201+
$state = 'UNDETERMINED';
202+
}
203+
$response->headers->set('X-Cache', $state);
204+
}
205+
206+
return $response;
207+
}
208+
209+
The ``UNDETERMINED`` state should never happen. If it does, it means that your
210+
HttpCache is not correctly set into debug mode.
211+
182212
.. _HttpCache: http://symfony.com/doc/current/book/http_cache.html#symfony-reverse-proxy

doc/testing-your-application.rst

Lines changed: 136 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,30 @@ Testing Your Application
44
========================
55

66
This chapter describes how to test your application against your reverse proxy.
7-
8-
The FOSHttpCache library provides base test case classes to help you write
9-
functional tests. This is helpful to test the way your application sets caching
10-
headers and invalidates cached content.
11-
12-
By having your test classes extend one of the test case classes, you get:
13-
14-
* independent tests: all previously cached content is removed in the tests
15-
``setUp`` method. The way this is done depends on which reverse proxy you use;
16-
* an instance of this library’s client that is configured to talk to your
17-
reverse proxy server. See reverse proxy specific sections for details;
18-
* convenience methods for executing HTTP requests to your application:
19-
``$this->getHttpAdapter()`` and ``$this->getResponse()``;
20-
* custom assertions ``assertHit`` and ``assertMiss`` for validating a cache
7+
By running your tests against a live instance of your caching proxy, you can
8+
validate the caching headers that your application sets, and the invalidation
9+
rules that it defines.
10+
11+
The FOSHttpCache library provides traits and base test classes to help you write
12+
functional tests. Using the traits, you can extend your own (or your
13+
framework’s) base test classes. For convenience, you can also extend the
14+
FOSHttpCache base test classes, as they include a sensible set of traits by
15+
default.
16+
17+
By using the traits, you get:
18+
19+
* independent tests: all previously cached content is removed in the test’s
20+
``setUp()`` method;
21+
* an instance of this library’s proxy client that is configured to talk to your
22+
proxy server for invalidation requests;
23+
* a convenience method for executing HTTP requests to your caching proxy:
24+
``$this->getResponse()``;
25+
* custom assertions ``assertHit()`` and ``assertMiss()`` for validating a cache
2126
hit/miss.
2227

28+
Configuration
29+
-------------
30+
2331
The recommended way to configure the test case is by setting constants
2432
in your ``phpunit.xml``. Alternatively, you can override the getter methods.
2533

@@ -56,89 +64,69 @@ You can override getters in your test class in the following way::
5664
}
5765
}
5866

59-
VarnishTestCase
60-
---------------
67+
Traits
68+
------
6169

62-
Configuration
63-
'''''''''''''
70+
Caching Proxy Server Traits
71+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
72+
73+
FOSHttpCache provides three caching proxy traits that:
74+
75+
* if necessary, start your caching proxy server before running the tests;
76+
* clear any cached content between tests to guarantee test isolation;
77+
* if necessary, stop the caching proxy server after the tests have finished;
78+
* provide ``getProxyClient()``, which returns the right
79+
:doc:`proxy client <proxy-clients>` for your proxy server.
6480

65-
By default, the ``VarnishTestCase`` starts and stops a Varnish server for you.
66-
Make sure ``symfony/process`` is available in your project:
81+
You only need to include one of these traits in your test classes. Which one
82+
you need (``VarnishTest``, ``NginxTest`` or ``SymfonyTest``) depends on the
83+
caching proxy server that you use.
6784

68-
.. code-block:: bash
85+
VarnishTest Trait
86+
"""""""""""""""""
6987

70-
$ composer require symfony/process
88+
.. include:: includes/symfony-process.rst
7189

72-
Then set your Varnish configuration (VCL) file. All available configuration
73-
parameters are shown below.
90+
Then configure the following parameters. The web server hostname and path to
91+
your VCL file are required.
7492

7593
======================= ========================= ================================================== ===========================================
7694
Constant Getter Default Description
7795
======================= ========================= ================================================== ===========================================
96+
``WEB_SERVER_HOSTNAME`` ``getHostName()`` hostname your application can be reached at
7897
``VARNISH_FILE`` ``getConfigFile()`` your Varnish configuration (VCL) file
7998
``VARNISH_BINARY`` ``getBinary()`` ``varnishd`` your Varnish binary
8099
``VARNISH_PORT`` ``getCachingProxyPort()`` ``6181`` port Varnish listens on
81100
``VARNISH_MGMT_PORT`` ``getVarnishMgmtPort()`` ``6182`` Varnish management port
82101
``VARNISH_CACHE_DIR`` ``getCacheDir()`` ``sys_get_temp_dir()`` + ``/foshttpcache-varnish`` directory to use for cache
83102
``VARNISH_VERSION`` ``getVarnishVersion()`` ``4`` installed varnish application version
84-
``WEB_SERVER_HOSTNAME`` ``getHostName()`` hostname your application can be reached at
85103
======================= ========================= ================================================== ===========================================
86104

87-
Enable Assertions
88-
'''''''''''''''''
89-
90-
For the `assertHit` and `assertMiss` assertions to work, you need to add a
91-
:ref:`custom X-Cache header <varnish_debugging>` to responses served
92-
by your Varnish.
105+
NginxTest Trait
106+
"""""""""""""""
93107

94-
NginxTestCase
95-
-------------
96-
97-
Configuration
98-
'''''''''''''
99-
100-
By default, the ``NginxTestCase`` starts and stops the NGINX server for you and
101-
deletes all cached contents. Make sure ``symfony/process`` is available in your
102-
project:
103-
104-
.. code-block:: bash
105-
106-
$ composer require symfony/process
108+
.. include:: includes/symfony-process.rst
107109

108-
You have to set your NGINX configuration file. All available configuration
109-
parameters are shown below.
110+
Then configure the following parameters. The web server hostname and path to
111+
your NGINX configuration file are required.
110112

111113
======================= ========================= ================================================ ===========================================
112114
Constant Getter Default Description
113115
======================= ========================= ================================================ ===========================================
116+
``WEB_SERVER_HOSTNAME`` ``getHostName()`` hostname your application can be reached at
114117
``NGINX_FILE`` ``getConfigFile()`` your NGINX configuration file
115118
``NGINX_BINARY`` ``getBinary()`` ``nginx`` your NGINX binary
116119
``NGINX_PORT`` ``getCachingProxyPort()`` ``8088`` port NGINX listens on
117120
``NGINX_CACHE_PATH`` ``getCacheDir()`` ``sys_get_temp_dir()`` + ``/foshttpcache-nginx`` directory to use for cache
118121
Must match `proxy_cache_path` directive in
119122
your configuration file.
120-
``WEB_SERVER_HOSTNAME`` ``getHostName()`` hostname your application can be reached at
121123
======================= ========================= ================================================ ===========================================
122124

123-
Enable Assertions
124-
'''''''''''''''''
125-
126-
For the `assertHit` and `assertMiss` assertions to work, you need to add a
127-
:ref:`custom X-Cache header <nginx_debugging>` to responses served
128-
by your Nginx.
125+
SymfonyTest Trait
126+
"""""""""""""""""
129127

130-
SymfonyTestCase
131-
---------------
132-
133-
This test case helps to test invalidation requests with a symfony application
134-
running the Symfony HttpCache and invalidating its cache folder to get reliable
135-
tests.
136-
137-
The ``SymfonyTestCase`` does automatically start a web server. It is assumed
138-
that the web server you run for the application has the HttpCache integrated.
139-
140-
Configuration
141-
'''''''''''''
128+
It is assumed that the web server you run for the application has the HttpCache
129+
integrated.
142130

143131
======================= ========================= ================================================ ===========================================
144132
Constant Getter Default Description
@@ -151,59 +139,92 @@ Constant Getter Default
151139
running PHPUnit.
152140
======================= ========================= ================================================ ===========================================
153141

154-
Enable Assertions
155-
'''''''''''''''''
142+
HttpCaller Trait
143+
~~~~~~~~~~~~~~~~
144+
145+
Provides your tests with a ``getResponse`` method, which retrieves a URI from
146+
your application through a real HTTP call that goes through the HTTP caching
147+
proxy::
156148

157-
For the `assertHit` and `assertMiss` assertions to work, you need to add debug
158-
information in your AppCache. Create the cache kernel with the option
159-
``'debug' => true`` and add the following to your ``AppCache``::
149+
use FOS\HttpCache\Test\HttpCaller;
160150

161-
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
151+
class YourTest extends \PHPUnit_Framework_TestCase
162152
{
163-
$response = parent::handle($request, $type, $catch);
164-
165-
if ($response->headers->has('X-Symfony-Cache')) {
166-
if (false !== strpos($response->headers->get('X-Symfony-Cache'), 'miss')) {
167-
$state = 'MISS';
168-
} elseif (false !== strpos($response->headers->get('X-Symfony-Cache'), 'fresh')) {
169-
$state = 'HIT';
170-
} else {
171-
$state = 'UNDETERMINED';
172-
}
173-
$response->headers->set('X-Cache', $state);
153+
public function testCachingHeaders()
154+
{
155+
// Get some response from your application
156+
$response = $this->getResponse('/path');
157+
158+
// Optionally with request headers and a custom method
159+
$response = $this->getResponse('/path', ['Accept' => 'text/json'], 'PUT');
174160
}
161+
}
175162

176-
return $response;
163+
CacheAssertions Trait
164+
~~~~~~~~~~~~~~~~~~~~~
165+
166+
Provides cache hit/miss assertions to your tests. To enable the these
167+
``assertHit`` and ``assertMiss`` assertions, you need to configure your caching
168+
server to set an `X-Cache` header with the cache status:
169+
170+
* :ref:`Varnish <varnish_debugging>`
171+
* :ref:`NGINX <nginx_debugging>`
172+
* :ref:`Symfony HttpCache <symfony-cache x-debugging>`
173+
174+
Then use the assertions as follows::
175+
176+
use FOS\HttpCache\Test\CacheAssertions;
177+
178+
class YourTest extends \PHPUnit_Framework_TestCase
179+
{
180+
public function testCacheHitOrMiss()
181+
{
182+
// Assert the application response is a cache miss
183+
$this->assertMiss($response);
184+
185+
// Or assert it is a hit
186+
$this->assertHit($response);
187+
}
177188
}
178189

179-
The ``UNDETERMINED`` state should never happen. If it does, it means that your
180-
HttpCache is not correctly set into debug mode.
190+
Base Classes for Convenience
191+
----------------------------
192+
193+
If you prefer, you can extend your test classes from ``VarnishTestCase``,
194+
``NginxTestCase`` or ``SymfonyTestCase``. The appropriate traits will then
195+
automatically be included.
181196

182197
Usage
183198
-----
184199

185200
This example shows how you can test whether the caching headers your
186-
application sets influence Varnish as you expect them to::
201+
application sets influence your caching proxy as you expect them to::
187202

188-
use FOS\HttpCache\Test\VarnishTestCase;
203+
use FOS\HttpCache\Test\CacheAssertions;
204+
use FOS\HttpCache\Test\HttpCaller;
205+
use FOS\HttpCache\Test\VarnishTest;
206+
// or FOS\HttpCache\Test\NginxTest;
207+
// or FOS\HttpCache\Test\SymfonyTest;
189208

190-
class YourFunctionalTest extends VarnishTestCase
209+
class YourTest extends \PHPUnit_Framework_TestCase
191210
{
192211
public function testCachingHeaders()
193212
{
194-
// Varnish is restarted, so you don’t have to worry about previously
195-
// cached content. Before continuing, the VarnishTestCase waits for
196-
// Varnish to become available.
213+
// The caching proxy is (re)started, so you don’t have to worry
214+
// about previously cached content. Before continuing, the
215+
// VarnishTest/ NginxTest trait waits for the caching proxy to
216+
// become available.
197217

198-
// Retrieve an URL from your application
218+
// Retrieve a URL from your application
199219
$response = $this->getResponse('/your/resource');
200220

201221
// Assert the response was a cache miss (came from the backend
202222
// application)
203223
$this->assertMiss($response);
204224

205-
// Assume the URL /your/resource sets caching headers. If we retrieve
206-
// it again, we should have a cache hit (response delivered by Varnish):
225+
// Assume the URL /your/resource sets caching headers. If we
226+
// retrieve it again, we should have a cache hit (response delivered
227+
// by the caching proxy):
207228
$response = $this->getResponse('/your/resource');
208229
$this->assertHit($response);
209230
}
@@ -212,26 +233,34 @@ application sets influence Varnish as you expect them to::
212233
This example shows how you can test whether your application purges content
213234
correctly::
214235

215-
public function testCachePurge()
236+
use FOS\HttpCache\Test\CacheAssertions;
237+
use FOS\HttpCache\Test\HttpCaller;
238+
use FOS\HttpCache\Test\VarnishTest;
239+
// or FOS\HttpCache\Test\NginxTest;
240+
// or FOS\HttpCache\Test\SymfonyTest;
241+
242+
class YourTest extends \PHPUnit_Framework_TestCase
216243
{
217-
// Again, Varnish is restarted, so your test is independent from
218-
// other tests
244+
public function testCachePurge()
245+
{
246+
// Again, the caching proxy is restarted, so your test is independent
247+
// from other tests
219248

220-
$url = '/blog/articles/1';
249+
$url = '/blog/articles/1';
221250

222-
// First request must be a cache miss
223-
$this->assertMiss($this->getResponse($url));
251+
// First request must be a cache miss
252+
$this->assertMiss($this->getResponse($url));
224253

225-
// Next requests must be a hit
226-
$this->assertHit($this->getResponse($url));
254+
// Next requests must be a hit
255+
$this->assertHit($this->getResponse($url));
227256

228-
// Purge
229-
$this->varnish->purge('/blog/articles/1');
257+
// Purge
258+
$this->getProxyClient()->purge('/blog/articles/1');
230259

231-
// First request after must again be a miss
232-
$this->assertMiss($this->getResponse($url));
260+
// First request after must again be a miss
261+
$this->assertMiss($this->getResponse($url));
262+
}
233263
}
234264

235-
Tests for Nginx look the same but extend the NginxTestCase.
236265
For more ideas, see this library’s functional tests in the
237266
:source:`tests/Functional/` directory.

0 commit comments

Comments
 (0)