Merge "Add semantic tags to license info text"
[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 use MediaWikiCoversValidator;
30
31 /**
32 * @covers XhprofData::splitKey
33 * @dataProvider provideSplitKey
34 */
35 public function testSplitKey( $key, $expect ) {
36 $this->assertSame( $expect, XhprofData::splitKey( $key ) );
37 }
38
39 public function provideSplitKey() {
40 return [
41 [ 'main()', [ null, 'main()' ] ],
42 [ 'foo==>bar', [ 'foo', 'bar' ] ],
43 [ 'bar@1==>bar@2', [ 'bar@1', 'bar@2' ] ],
44 [ 'foo==>bar==>baz', [ 'foo', 'bar==>baz' ] ],
45 [ '==>bar', [ '', 'bar' ] ],
46 [ '', [ null, '' ] ],
47 ];
48 }
49
50 /**
51 * @covers XhprofData::pruneData
52 */
53 public function testInclude() {
54 $xhprofData = $this->getXhprofDataFixture( [
55 'include' => [ 'main()' ],
56 ] );
57 $raw = $xhprofData->getRawData();
58 $this->assertArrayHasKey( 'main()', $raw );
59 $this->assertArrayHasKey( 'main()==>foo', $raw );
60 $this->assertArrayHasKey( 'main()==>xhprof_disable', $raw );
61 $this->assertSame( 3, count( $raw ) );
62 }
63
64 /**
65 * Validate the structure of data returned by
66 * Xhprof::getInclusiveMetrics(). This acts as a guard against unexpected
67 * structural changes to the returned data in lieu of using a more heavy
68 * weight typed response object.
69 *
70 * @covers XhprofData::getInclusiveMetrics
71 */
72 public function testInclusiveMetricsStructure() {
73 $metricStruct = [
74 'ct' => 'int',
75 'wt' => 'array',
76 'cpu' => 'array',
77 'mu' => 'array',
78 'pmu' => 'array',
79 ];
80 $statStruct = [
81 'total' => 'numeric',
82 'min' => 'numeric',
83 'mean' => 'numeric',
84 'max' => 'numeric',
85 'variance' => 'numeric',
86 'percent' => 'numeric',
87 ];
88
89 $xhprofData = $this->getXhprofDataFixture();
90 $metrics = $xhprofData->getInclusiveMetrics();
91
92 foreach ( $metrics as $name => $metric ) {
93 $this->assertArrayStructure( $metricStruct, $metric );
94
95 foreach ( $metricStruct as $key => $type ) {
96 if ( $type === 'array' ) {
97 $this->assertArrayStructure( $statStruct, $metric[$key] );
98 if ( $name === 'main()' ) {
99 $this->assertEquals( 100, $metric[$key]['percent'] );
100 }
101 }
102 }
103 }
104 }
105
106 /**
107 * Validate the structure of data returned by
108 * Xhprof::getCompleteMetrics(). This acts as a guard against unexpected
109 * structural changes to the returned data in lieu of using a more heavy
110 * weight typed response object.
111 *
112 * @covers XhprofData::getCompleteMetrics
113 */
114 public function testCompleteMetricsStructure() {
115 $metricStruct = [
116 'ct' => 'int',
117 'wt' => 'array',
118 'cpu' => 'array',
119 'mu' => 'array',
120 'pmu' => 'array',
121 'calls' => 'array',
122 'subcalls' => 'array',
123 ];
124 $statsMetrics = [ 'wt', 'cpu', 'mu', 'pmu' ];
125 $statStruct = [
126 'total' => 'numeric',
127 'min' => 'numeric',
128 'mean' => 'numeric',
129 'max' => 'numeric',
130 'variance' => 'numeric',
131 'percent' => 'numeric',
132 'exclusive' => 'numeric',
133 ];
134
135 $xhprofData = $this->getXhprofDataFixture();
136 $metrics = $xhprofData->getCompleteMetrics();
137
138 foreach ( $metrics as $name => $metric ) {
139 $this->assertArrayStructure( $metricStruct, $metric, $name );
140
141 foreach ( $metricStruct as $key => $type ) {
142 if ( in_array( $key, $statsMetrics ) ) {
143 $this->assertArrayStructure(
144 $statStruct, $metric[$key], $key
145 );
146 $this->assertLessThanOrEqual(
147 $metric[$key]['total'], $metric[$key]['exclusive']
148 );
149 }
150 }
151 }
152 }
153
154 /**
155 * @covers XhprofData::getCallers
156 * @covers XhprofData::getCallees
157 * @uses XhprofData
158 */
159 public function testEdges() {
160 $xhprofData = $this->getXhprofDataFixture();
161 $this->assertSame( [], $xhprofData->getCallers( 'main()' ) );
162 $this->assertSame( [ 'foo', 'xhprof_disable' ],
163 $xhprofData->getCallees( 'main()' )
164 );
165 $this->assertSame( [ 'main()' ],
166 $xhprofData->getCallers( 'foo' )
167 );
168 $this->assertSame( [], $xhprofData->getCallees( 'strlen' ) );
169 }
170
171 /**
172 * @covers XhprofData::getCriticalPath
173 * @uses XhprofData
174 */
175 public function testCriticalPath() {
176 $xhprofData = $this->getXhprofDataFixture();
177 $path = $xhprofData->getCriticalPath();
178
179 $last = null;
180 foreach ( $path as $key => $value ) {
181 list( $func, $call ) = XhprofData::splitKey( $key );
182 $this->assertSame( $last, $func );
183 $last = $call;
184 }
185 $this->assertSame( $last, 'bar@1' );
186 }
187
188 /**
189 * Get an Xhprof instance that has been primed with a set of known testing
190 * data. Tests for the Xhprof class should laregly be concerned with
191 * evaluating the manipulations of the data collected by xhprof rather
192 * than the data collection process itself.
193 *
194 * The returned Xhprof instance primed will be with a data set created by
195 * running this trivial program using the PECL xhprof implementation:
196 * @code
197 * function bar( $x ) {
198 * if ( $x > 0 ) {
199 * bar($x - 1);
200 * }
201 * }
202 * function foo() {
203 * for ( $idx = 0; $idx < 2; $idx++ ) {
204 * bar( $idx );
205 * $x = strlen( 'abc' );
206 * }
207 * }
208 * xhprof_enable( XHPROF_FLAGS_CPU | XHPROF_FLAGS_MEMORY );
209 * foo();
210 * $x = xhprof_disable();
211 * var_export( $x );
212 * @endcode
213 *
214 * @return Xhprof
215 */
216 protected function getXhprofDataFixture( array $opts = [] ) {
217 return new XhprofData( [
218 'foo==>bar' => [
219 'ct' => 2,
220 'wt' => 57,
221 'cpu' => 92,
222 'mu' => 1896,
223 'pmu' => 0,
224 ],
225 'foo==>strlen' => [
226 'ct' => 2,
227 'wt' => 21,
228 'cpu' => 141,
229 'mu' => 752,
230 'pmu' => 0,
231 ],
232 'bar==>bar@1' => [
233 'ct' => 1,
234 'wt' => 18,
235 'cpu' => 19,
236 'mu' => 752,
237 'pmu' => 0,
238 ],
239 'main()==>foo' => [
240 'ct' => 1,
241 'wt' => 304,
242 'cpu' => 307,
243 'mu' => 4008,
244 'pmu' => 0,
245 ],
246 'main()==>xhprof_disable' => [
247 'ct' => 1,
248 'wt' => 8,
249 'cpu' => 10,
250 'mu' => 768,
251 'pmu' => 392,
252 ],
253 'main()' => [
254 'ct' => 1,
255 'wt' => 353,
256 'cpu' => 351,
257 'mu' => 6112,
258 'pmu' => 1424,
259 ],
260 ], $opts );
261 }
262
263 /**
264 * Assert that the given array has the described structure.
265 *
266 * @param array $struct Array of key => type mappings
267 * @param array $actual Array to check
268 * @param string $label
269 */
270 protected function assertArrayStructure( $struct, $actual, $label = null ) {
271 $this->assertInternalType( 'array', $actual, $label );
272 $this->assertCount( count( $struct ), $actual, $label );
273 foreach ( $struct as $key => $type ) {
274 $this->assertArrayHasKey( $key, $actual );
275 $this->assertInternalType( $type, $actual[$key] );
276 }
277 }
278 }