Completed
Push — master ( 3c91a9...7f2ec8 )
by Jérémy
11s
created

testOnKernelResponseOnlyMasterRequestsAreProcessed()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

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