Passed
Push — master ( 8cd72e...2db2f3 )
by Tobias
02:40
created

Tests/Listener/ResponseListenerTest.php (4 issues)

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Ekino New Relic bundle.
7
 *
8
 * (c) Ekino - Thomas Rabaix <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Ekino\NewRelicBundle\Tests\Listener;
15
16
use Ekino\NewRelicBundle\Listener\ResponseListener;
17
use Ekino\NewRelicBundle\NewRelic\Config;
18
use Ekino\NewRelicBundle\NewRelic\NewRelicInteractorInterface;
19
use Ekino\NewRelicBundle\Twig\NewRelicExtension;
20
use PHPUnit\Framework\TestCase;
0 ignored issues
show
The type PHPUnit\Framework\TestCase was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
21
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
22
23
class ResponseListenerTest extends TestCase
24
{
25
    protected function setUp()
26
    {
27
        $this->interactor = $this->getMockBuilder(NewRelicInteractorInterface::class)->getMock();
0 ignored issues
show
Bug Best Practice introduced by
The property interactor does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
28
        $this->newRelic = $this->getMockBuilder(Config::class)
0 ignored issues
show
Bug Best Practice introduced by
The property newRelic does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
29
            ->setMethods(['getCustomEvents', 'getCustomMetrics', 'getCustomParameters'])
30
            ->disableOriginalConstructor()
31
            ->getMock();
32
        $this->extension = $this->getMockBuilder(NewRelicExtension::class)
0 ignored issues
show
Bug Best Practice introduced by
The property extension does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
33
            ->setMethods(['isHeaderCalled', 'isFooterCalled', 'isUsed'])
34
            ->disableOriginalConstructor()
35
            ->getMock();
36
    }
37
38
    public function testOnKernelResponseOnlyMasterRequestsAreProcessed()
39
    {
40
        $event = $this->getMockBuilder(FilterResponseEvent::class)
41
            ->setMethods(['isMasterRequest'])
42
            ->disableOriginalConstructor()
43
            ->getMock();
44
        $event->method('isMasterRequest')->will($this->returnValue(false));
45
46
        $object = new ResponseListener($this->newRelic, $this->interactor);
47
        $object->onKernelResponse($event);
48
49
        $this->newRelic->expects($this->never())->method('getCustomMetrics');
50
    }
51
52
    public function testOnKernelResponseWithOnlyCustomMetricsAndParameters()
53
    {
54
        $events = [
55
            'WidgetSale' => [
56
                [
57
                    'color' => 'red',
58
                    'weight' => 12.5,
59
                ],
60
                [
61
                    'color' => 'blue',
62
                    'weight' => 12.5,
63
                ],
64
            ],
65
        ];
66
67
        $metrics = [
68
            'foo_a' => 4.7,
69
            'foo_b' => 11,
70
        ];
71
72
        $parameters = [
73
            'foo_1' => 'bar_1',
74
            'foo_2' => 'bar_2',
75
        ];
76
77
        $this->newRelic->expects($this->once())->method('getCustomEvents')->will($this->returnValue($events));
78
        $this->newRelic->expects($this->once())->method('getCustomMetrics')->will($this->returnValue($metrics));
79
        $this->newRelic->expects($this->once())->method('getCustomParameters')->will($this->returnValue($parameters));
80
81
        $this->interactor->expects($this->at(0))->method('addCustomMetric')->with('foo_a', 4.7);
82
        $this->interactor->expects($this->at(1))->method('addCustomMetric')->with('foo_b', 11);
83
        $this->interactor->expects($this->at(2))->method('addCustomParameter')->with('foo_1', 'bar_1');
84
        $this->interactor->expects($this->at(3))->method('addCustomParameter')->with('foo_2', 'bar_2');
85
86
        $this->interactor->expects($this->at(4))->method('addCustomEvent')->with('WidgetSale', [
87
            'color' => 'red',
88
            'weight' => 12.5,
89
        ]);
90
        $this->interactor->expects($this->at(5))->method('addCustomEvent')->with('WidgetSale', [
91
            'color' => 'blue',
92
            'weight' => 12.5,
93
        ]);
94
95
        $event = $this->createFilterResponseEventMock();
96
97
        $object = new ResponseListener($this->newRelic, $this->interactor, false);
98
        $object->onKernelResponse($event);
99
    }
100
101
    public function testOnKernelResponseInstrumentDisabledInRequest()
102
    {
103
        $this->setupNoCustomMetricsOrParameters();
104
105
        $this->interactor->expects($this->once())->method('disableAutoRUM');
106
107
        $request = $this->createRequestMock(false);
108
        $event = $this->createFilterResponseEventMock($request, null);
109
110
        $object = new ResponseListener($this->newRelic, $this->interactor, true);
111
        $object->onKernelResponse($event);
112
    }
113
114
    public function testSymfonyCacheEnabled()
115
    {
116
        $this->setupNoCustomMetricsOrParameters();
117
118
        $this->interactor->expects($this->once())->method('endTransaction');
119
120
        $request = $this->createRequestMock(false);
121
        $event = $this->createFilterResponseEventMock($request, null);
122
123
        $object = new ResponseListener($this->newRelic, $this->interactor, false, true);
124
        $object->onKernelResponse($event);
125
    }
126
127
    public function testSymfonyCacheDisabled()
128
    {
129
        $this->setupNoCustomMetricsOrParameters();
130
131
        $this->interactor->expects($this->never())->method('endTransaction');
132
133
        $request = $this->createRequestMock(false);
134
        $event = $this->createFilterResponseEventMock($request, null);
135
136
        $object = new ResponseListener($this->newRelic, $this->interactor, false, false);
137
        $object->onKernelResponse($event);
138
    }
139
140
    /**
141
     * @dataProvider providerOnKernelResponseOnlyInstrumentHTMLResponses
142
     */
143
    public function testOnKernelResponseOnlyInstrumentHTMLResponses($content, $expectsSetContent, $contentType)
144
    {
145
        $this->setupNoCustomMetricsOrParameters();
146
147
        $this->interactor->expects($this->once())->method('disableAutoRUM');
148
        $this->interactor->expects($this->any())->method('getBrowserTimingHeader')->will($this->returnValue('__Timing_Header__'));
149
        $this->interactor->expects($this->any())->method('getBrowserTimingFooter')->will($this->returnValue('__Timing_Feader__'));
150
151
        $request = $this->createRequestMock();
152
        $response = $this->createResponseMock($content, $expectsSetContent, $contentType);
153
        $event = $this->createFilterResponseEventMock($request, $response);
154
155
        $object = new ResponseListener($this->newRelic, $this->interactor, true);
156
        $object->onKernelResponse($event);
157
    }
158
159
    public function providerOnKernelResponseOnlyInstrumentHTMLResponses()
160
    {
161
        return [
162
            // unsupported content types
163
            [null, null, 'text/xml'],
164
            [null, null, 'text/plain'],
165
            [null, null, 'application/json'],
166
167
            ['content', 'content', 'text/html'],
168
            ['<div class="head">head</div>', '<div class="head">head</div>', 'text/html'],
169
            ['<header>content</header>', '<header>content</header>', 'text/html'],
170
171
            // head, body tags
172
            ['<head><title /></head>', '<head>__Timing_Header__<title /></head>', 'text/html'],
173
            ['<body><div /></body>', '<body><div />__Timing_Feader__</body>', 'text/html'],
174
            ['<head><title /></head><body><div /></body>', '<head>__Timing_Header__<title /></head><body><div />__Timing_Feader__</body>', 'text/html'],
175
176
            // with charset
177
            ['<head><title /></head><body><div /></body>', '<head>__Timing_Header__<title /></head><body><div />__Timing_Feader__</body>', 'text/html; charset=UTF-8'],
178
        ];
179
    }
180
181
    public function testInteractionWithTwigExtensionHeader()
182
    {
183
        $this->newRelic->expects($this->never())->method('getCustomMetrics');
184
        $this->newRelic->expects($this->never())->method('getCustomParameters');
185
        $this->newRelic->expects($this->once())->method('getCustomEvents')->will($this->returnValue([]));
186
187
        $this->interactor->expects($this->never())->method('disableAutoRUM');
188
        $this->interactor->expects($this->never())->method('getBrowserTimingHeader');
189
        $this->interactor->expects($this->once())->method('getBrowserTimingFooter')->will($this->returnValue('__Timing_Feader__'));
190
191
        $this->extension->expects($this->exactly(2))->method('isUsed')->will($this->returnValue(true));
192
        $this->extension->expects($this->once())->method('isHeaderCalled')->will($this->returnValue(true));
193
        $this->extension->expects($this->once())->method('isFooterCalled')->will($this->returnValue(false));
194
195
        $request = $this->createRequestMock(true);
196
        $response = $this->createResponseMock('content', 'content', 'text/html');
197
        $event = $this->createFilterResponseEventMock($request, $response);
198
199
        $object = new ResponseListener($this->newRelic, $this->interactor, true, false, $this->extension);
200
        $object->onKernelResponse($event);
201
    }
202
203
    public function testInteractionWithTwigExtensionFooter()
204
    {
205
        $this->newRelic->expects($this->never())->method('getCustomMetrics');
206
        $this->newRelic->expects($this->never())->method('getCustomParameters');
207
        $this->newRelic->expects($this->once())->method('getCustomEvents')->will($this->returnValue([]));
208
209
        $this->interactor->expects($this->never())->method('disableAutoRUM');
210
        $this->interactor->expects($this->once())->method('getBrowserTimingHeader')->will($this->returnValue('__Timing_Feader__'));
211
        $this->interactor->expects($this->never())->method('getBrowserTimingFooter');
212
213
        $this->extension->expects($this->exactly(2))->method('isUsed')->will($this->returnValue(true));
214
        $this->extension->expects($this->once())->method('isHeaderCalled')->will($this->returnValue(false));
215
        $this->extension->expects($this->once())->method('isFooterCalled')->will($this->returnValue(true));
216
217
        $request = $this->createRequestMock(true);
218
        $response = $this->createResponseMock('content', 'content', 'text/html');
219
        $event = $this->createFilterResponseEventMock($request, $response);
220
221
        $object = new ResponseListener($this->newRelic, $this->interactor, true, false, $this->extension);
222
        $object->onKernelResponse($event);
223
    }
224
225
    public function testInteractionWithTwigExtensionHeaderFooter()
226
    {
227
        $this->newRelic->expects($this->never())->method('getCustomMetrics');
228
        $this->newRelic->expects($this->never())->method('getCustomParameters');
229
        $this->newRelic->expects($this->once())->method('getCustomEvents')->will($this->returnValue([]));
230
231
        $this->interactor->expects($this->never())->method('disableAutoRUM');
232
        $this->interactor->expects($this->never())->method('getBrowserTimingHeader');
233
        $this->interactor->expects($this->never())->method('getBrowserTimingFooter');
234
235
        $this->extension->expects($this->exactly(2))->method('isUsed')->will($this->returnValue(true));
236
        $this->extension->expects($this->once())->method('isHeaderCalled')->will($this->returnValue(true));
237
        $this->extension->expects($this->once())->method('isFooterCalled')->will($this->returnValue(true));
238
239
        $request = $this->createRequestMock(true);
240
        $response = $this->createResponseMock('content', 'content', 'text/html');
241
        $event = $this->createFilterResponseEventMock($request, $response);
242
243
        $object = new ResponseListener($this->newRelic, $this->interactor, true, false, $this->extension);
244
        $object->onKernelResponse($event);
245
    }
246
247
    private function setUpNoCustomMetricsOrParameters()
248
    {
249
        $this->newRelic->expects($this->once())->method('getCustomEvents')->will($this->returnValue([]));
250
        $this->newRelic->expects($this->once())->method('getCustomMetrics')->will($this->returnValue([]));
251
        $this->newRelic->expects($this->once())->method('getCustomParameters')->will($this->returnValue([]));
252
253
        $this->interactor->expects($this->never())->method('addCustomEvent');
254
        $this->interactor->expects($this->never())->method('addCustomMetric');
255
        $this->interactor->expects($this->never())->method('addCustomParameter');
256
    }
257
258
    private function createRequestMock($instrumentEnabled = true)
259
    {
260
        $mock = $this->getMockBuilder('stdClass')
261
            ->setMethods(['get'])
262
            ->getMock();
263
        $mock->attributes = $mock;
264
265
        $mock->expects($this->any())->method('get')->will($this->returnValue($instrumentEnabled));
266
267
        return $mock;
268
    }
269
270
    private function createResponseMock($content = null, $expectsSetContent = null, $contentType = 'text/html')
271
    {
272
        $mock = $this->getMockBuilder('stdClass')
273
            ->setMethods(['get', 'getContent', 'setContent'])
274
            ->getMock();
275
        $mock->headers = $mock;
276
277
        $mock->expects($this->any())->method('get')->will($this->returnValue($contentType));
278
        $mock->expects($content ? $this->any() : $this->never())->method('getContent')->will($this->returnValue($content));
279
280
        if ($expectsSetContent) {
281
            $mock->expects($this->once())->method('setContent')->with($expectsSetContent);
282
        } else {
283
            $mock->expects($this->never())->method('setContent');
284
        }
285
286
        return $mock;
287
    }
288
289
    private function createFilterResponseEventMock($request = null, $response = null)
290
    {
291
        $event = $this->getMockBuilder(FilterResponseEvent::class)
292
            ->setMethods(['getResponse', 'getRequest', 'isMasterRequest'])
293
            ->disableOriginalConstructor()
294
            ->getMock();
295
296
        $event->expects($request ? $this->any() : $this->never())->method('getRequest')->will($this->returnValue($request));
297
        $event->expects($response ? $this->any() : $this->never())->method('getResponse')->will($this->returnValue($response));
298
        $event->method('isMasterRequest')->will($this->returnValue(true));
299
300
        return $event;
301
    }
302
}
303