Merge "User: Avoid deprecated Linker::link()"
[lhc/web/wiklou.git] / tests / phpunit / includes / libs / XhprofDataTest.php
1 <?php
2 /**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
17 *
18 * @file
19 */
20
21 /**
22 * @uses XhprofData
23 * @uses AutoLoader
24 * @copyright © 2014 Wikimedia Foundation and contributors
25 * @since 1.25
26 */
27 class XhprofDataTest extends PHPUnit_Framework_TestCase {
28
29 /**
30 * @covers XhprofData::splitKey
31 * @dataProvider provideSplitKey
32 */
33 public function testSplitKey( $key, $expect ) {
34 $this->assertSame( $expect, XhprofData::splitKey( $key ) );
35 }
36
37 public function provideSplitKey() {
38 return [
39 [ 'main()', [ null, 'main()' ] ],
40 [ 'foo==>bar', [ 'foo', 'bar' ] ],
41 [ 'bar@1==>bar@2', [ 'bar@1', 'bar@2' ] ],
42 [ 'foo==>bar==>baz', [ 'foo', 'bar==>baz' ] ],
43 [ '==>bar', [ '', 'bar' ] ],
44 [ '', [ null, '' ] ],
45 ];
46 }
47
48 /**
49 * @covers XhprofData::pruneData
50 */
51 public function testInclude() {
52 $xhprofData = $this->getXhprofDataFixture( [
53 'include' => [ 'main()' ],
54 ] );
55 $raw = $xhprofData->getRawData();
56 $this->assertArrayHasKey( 'main()', $raw );
57 $this->assertArrayHasKey( 'main()==>foo', $raw );
58 $this->assertArrayHasKey( 'main()==>xhprof_disable', $raw );
59 $this->assertSame( 3, count( $raw ) );
60 }
61
62 /**
63 * Validate the structure of data returned by
64 * Xhprof::getInclusiveMetrics(). This acts as a guard against unexpected
65 * structural changes to the returned data in lieu of using a more heavy
66 * weight typed response object.
67 *
68 * @covers XhprofData::getInclusiveMetrics
69 */
70 public function testInclusiveMetricsStructure() {
71 $metricStruct = [
72 'ct' => 'int',
73 'wt' => 'array',
74 'cpu' => 'array',
75 'mu' => 'array',
76 'pmu' => 'array',
77 ];
78 $statStruct = [
79 'total' => 'numeric',
80 'min' => 'numeric',
81 'mean' => 'numeric',
82 'max' => 'numeric',
83 'variance' => 'numeric',
84 'percent' => 'numeric',
85 ];
86
87 $xhprofData = $this->getXhprofDataFixture();
88 $metrics = $xhprofData->getInclusiveMetrics();
89
90 foreach ( $metrics as $name => $metric ) {
91 $this->assertArrayStructure( $metricStruct, $metric );
92
93 foreach ( $metricStruct as $key => $type ) {
94 if ( $type === 'array' ) {
95 $this->assertArrayStructure( $statStruct, $metric[$key] );
96 if ( $name === 'main()' ) {
97 $this->assertEquals( 100, $metric[$key]['percent'] );
98 }
99 }
100 }
101 }
102 }
103
104 /**
105 * Validate the structure of data returned by
106 * Xhprof::getCompleteMetrics(). This acts as a guard against unexpected
107 * structural changes to the returned data in lieu of using a more heavy
108 * weight typed response object.
109 *
110 * @covers XhprofData::getCompleteMetrics
111 */
112 public function testCompleteMetricsStructure() {
113 $metricStruct = [
114 'ct' => 'int',
115 'wt' => 'array',
116 'cpu' => 'array',
117 'mu' => 'array',
118 'pmu' => 'array',
119 'calls' => 'array',
120 'subcalls' => 'array',
121 ];
122 $statsMetrics = [ 'wt', 'cpu', 'mu', 'pmu' ];
123 $statStruct = [
124 'total' => 'numeric',
125 'min' => 'numeric',
126 'mean' => 'numeric',
127 'max' => 'numeric',
128 'variance' => 'numeric',
129 'percent' => 'numeric',
130 'exclusive' => 'numeric',
131 ];
132
133 $xhprofData = $this->getXhprofDataFixture();
134 $metrics = $xhprofData->getCompleteMetrics();
135
136 foreach ( $metrics as $name => $metric ) {
137 $this->assertArrayStructure( $metricStruct, $metric, $name );
138
139 foreach ( $metricStruct as $key => $type ) {
140 if ( in_array( $key, $statsMetrics ) ) {
141 $this->assertArrayStructure(
142 $statStruct, $metric[$key], $key
143 );
144 $this->assertLessThanOrEqual(
145 $metric[$key]['total'], $metric[$key]['exclusive']
146 );
147 }
148 }
149 }
150 }
151
152 /**
153 * @covers XhprofData::getCallers
154 * @covers XhprofData::getCallees
155 * @uses XhprofData
156 */
157 public function testEdges() {
158 $xhprofData = $this->getXhprofDataFixture();
159 $this->assertSame( [], $xhprofData->getCallers( 'main()' ) );
160 $this->assertSame( [ 'foo', 'xhprof_disable' ],
161 $xhprofData->getCallees( 'main()' )
162 );
163 $this->assertSame( [ 'main()' ],
164 $xhprofData->getCallers( 'foo' )
165 );
166 $this->assertSame( [], $xhprofData->getCallees( 'strlen' ) );
167 }
168
169 /**
170 * @covers XhprofData::getCriticalPath
171 * @uses XhprofData
172 */
173 public function testCriticalPath() {
174 $xhprofData = $this->getXhprofDataFixture();
175 $path = $xhprofData->getCriticalPath();
176
177 $last = null;
178 foreach ( $path as $key => $value ) {
179 list( $func, $call ) = XhprofData::splitKey( $key );
180 $this->assertSame( $last, $func );
181 $last = $call;
182 }
183 $this->assertSame( $last, 'bar@1' );
184 }
185
186 /**
187 * Get an Xhprof instance that has been primed with a set of known testing
188 * data. Tests for the Xhprof class should laregly be concerned with
189 * evaluating the manipulations of the data collected by xhprof rather
190 * than the data collection process itself.
191 *
192 * The returned Xhprof instance primed will be with a data set created by
193 * running this trivial program using the PECL xhprof implementation:
194 * @code
195 * function bar( $x ) {
196 * if ( $x > 0 ) {
197 * bar($x - 1);
198 * }
199 * }
200 * function foo() {
201 * for ( $idx = 0; $idx < 2; $idx++ ) {
202 * bar( $idx );
203 * $x = strlen( 'abc' );
204 * }
205 * }
206 * xhprof_enable( XHPROF_FLAGS_CPU | XHPROF_FLAGS_MEMORY );
207 * foo();
208 * $x = xhprof_disable();
209 * var_export( $x );
210 * @endcode
211 *
212 * @return Xhprof
213 */
214 protected function getXhprofDataFixture( array $opts = [] ) {
215 return new XhprofData( [
216 'foo==>bar' => [
217 'ct' => 2,
218 'wt' => 57,
219 'cpu' => 92,
220 'mu' => 1896,
221 'pmu' => 0,
222 ],
223 'foo==>strlen' => [
224 'ct' => 2,
225 'wt' => 21,
226 'cpu' => 141,
227 'mu' => 752,
228 'pmu' => 0,
229 ],
230 'bar==>bar@1' => [
231 'ct' => 1,
232 'wt' => 18,
233 'cpu' => 19,
234 'mu' => 752,
235 'pmu' => 0,
236 ],
237 'main()==>foo' => [
238 'ct' => 1,
239 'wt' => 304,
240 'cpu' => 307,
241 'mu' => 4008,
242 'pmu' => 0,
243 ],
244 'main()==>xhprof_disable' => [
245 'ct' => 1,
246 'wt' => 8,
247 'cpu' => 10,
248 'mu' => 768,
249 'pmu' => 392,
250 ],
251 'main()' => [
252 'ct' => 1,
253 'wt' => 353,
254 'cpu' => 351,
255 'mu' => 6112,
256 'pmu' => 1424,
257 ],
258 ], $opts );
259 }
260
261 /**
262 * Assert that the given array has the described structure.
263 *
264 * @param array $struct Array of key => type mappings
265 * @param array $actual Array to check
266 * @param string $label
267 */
268 protected function assertArrayStructure( $struct, $actual, $label = null ) {
269 $this->assertInternalType( 'array', $actual, $label );
270 $this->assertCount( count( $struct ), $actual, $label );
271 foreach ( $struct as $key => $type ) {
272 $this->assertArrayHasKey( $key, $actual );
273 $this->assertInternalType( $type, $actual[$key] );
274 }
275 }
276 }