Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
0.00% |
0 / 203 |
|
0.00% |
0 / 16 |
CRAP | |
0.00% |
0 / 1 |
| AppStatsTest | |
0.00% |
0 / 202 |
|
0.00% |
0 / 16 |
552 | |
0.00% |
0 / 1 |
| setUpBeforeClass | |
0.00% |
0 / 27 |
|
0.00% |
0 / 1 |
6 | |||
| tearDownAfterClass | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| testStatsDefaultValues | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
| iterateObjectCheck0 | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
42 | |||
| testAppstatsMinute0 | |
0.00% |
0 / 23 |
|
0.00% |
0 / 1 |
2 | |||
| testAppstatsMinute1 | |
0.00% |
0 / 23 |
|
0.00% |
0 / 1 |
2 | |||
| testAppstatsHour0 | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
2 | |||
| testAppstatsDay0 | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
2 | |||
| testAppstatsMonth0 | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
2 | |||
| testAppstatsLimit0 | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
2 | |||
| testAppstatsLimit1 | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
2 | |||
| testAppstatsPagination0 | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
2 | |||
| testAppstatsPagination1 | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
2 | |||
| testAppstatsPagination2 | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
2 | |||
| testAppstatsPagination3 | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
2 | |||
| testPaginationDefaults | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
6 | |||
| 1 | <?php |
| 2 | namespace tests; |
| 3 | use Ably\AblyRest; |
| 4 | |
| 5 | require_once __DIR__ . '/factories/TestApp.php'; |
| 6 | |
| 7 | class AppStatsTest extends \PHPUnit_Framework_TestCase { |
| 8 | |
| 9 | protected static $testApp; |
| 10 | protected static $defaultOptions; |
| 11 | protected static $ably; |
| 12 | protected static $timestamp; |
| 13 | protected static $timestampOlder; |
| 14 | protected static $timestampMs; |
| 15 | protected static $timestampOlderMs; |
| 16 | |
| 17 | public static function setUpBeforeClass() { |
| 18 | self::$testApp = new TestApp(); |
| 19 | self::$defaultOptions = self::$testApp->getOptions(); |
| 20 | self::$ably = new AblyRest( array_merge( self::$defaultOptions, [ |
| 21 | 'key' => self::$testApp->getAppKeyDefault()->string, |
| 22 | ] ) ); |
| 23 | |
| 24 | self::$timestamp = strtotime( "first day of -1 month 14:00:00" ); |
| 25 | self::$timestampOlder = strtotime( "first day of -2 month 14:00:00" ); |
| 26 | self::$timestampMs = self::$timestamp * 1000; |
| 27 | self::$timestampOlderMs = self::$timestampOlder * 1000; |
| 28 | |
| 29 | $fixtureEntries = [ |
| 30 | '{ |
| 31 | "intervalId": "' . gmdate( 'Y-m-d:H:i', self::$timestamp ) . '", |
| 32 | "inbound": { "realtime": { "messages": { "count": 50, "data": 5000 } } }, |
| 33 | "outbound": { "realtime": { "messages": { "count": 20, "data": 2000 } } } |
| 34 | }', |
| 35 | '{ |
| 36 | "intervalId": "' . gmdate( 'Y-m-d:H:i', self::$timestamp + 60 ) . '", |
| 37 | "inbound": { "realtime": { "messages": { "count": 60, "data": 6000 } } }, |
| 38 | "outbound": { "realtime": { "messages": { "count": 10, "data": 1000 } } } |
| 39 | }', |
| 40 | '{ |
| 41 | "intervalId": "' . gmdate( 'Y-m-d:H:i', self::$timestamp + 120 ) . '", |
| 42 | "inbound": { "realtime": { "messages": { "count": 70, "data": 7000 } } }, |
| 43 | "outbound": { "realtime": { "messages": { "count": 40, "data": 4000 } } }, |
| 44 | "persisted": { "presence": { "count": 20, "data": 2000 } }, |
| 45 | "connections": { "tls": { "peak": 20, "opened": 10 } }, |
| 46 | "channels": { "peak": 50, "opened": 30 }, |
| 47 | "apiRequests": { "succeeded": 50, "failed": 10 }, |
| 48 | "tokenRequests": { "succeeded": 60, "failed": 20 } |
| 49 | }', |
| 50 | ]; |
| 51 | |
| 52 | for ($i = 0; $i < 101; $i++) { |
| 53 | $fixtureEntries[] = '{ |
| 54 | "intervalId": "' . gmdate( 'Y-m-d:H:i', self::$timestampOlder + $i * 60 ) . '", |
| 55 | "channels": { "peak": ' . ($i + 1) . ', "opened": 1 } |
| 56 | }'; |
| 57 | } |
| 58 | |
| 59 | $fixtureJSON = "[\n" . implode( ",\n", $fixtureEntries ) . "\n]"; |
| 60 | |
| 61 | self::$ably->post( '/stats', [], $fixtureJSON ); |
| 62 | } |
| 63 | |
| 64 | public static function tearDownAfterClass() { |
| 65 | self::$testApp->release(); |
| 66 | } |
| 67 | |
| 68 | /** |
| 69 | * Check if stats are automatically populated by zeroes |
| 70 | */ |
| 71 | public function testStatsDefaultValues() { |
| 72 | $stats = new \Ably\Models\Stats(); |
| 73 | $this->assertTrue( $this->iterateObjectCheck0( $stats ), 'Expected newly created Stats to have zero values.' ); |
| 74 | } |
| 75 | |
| 76 | protected function iterateObjectCheck0($obj, $level = 0) { |
| 77 | $valid = true; |
| 78 | |
| 79 | foreach ($obj as $key => $value) { |
| 80 | if (is_object($value)) { |
| 81 | if (!$this->iterateObjectCheck0($value, $level + 1)) $valid = false; |
| 82 | } else { |
| 83 | if ($level > 0 && $value !== 0) $valid = false; |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | return $valid; |
| 88 | } |
| 89 | |
| 90 | /** |
| 91 | * Check minute-level stats exist (forwards) |
| 92 | */ |
| 93 | public function testAppstatsMinute0() { |
| 94 | $oneMinuteMs = 60 * 1000; |
| 95 | $twoMinutesMs = 120 * 1000; |
| 96 | // get the stats for this channel |
| 97 | // note that bounds are inclusive |
| 98 | $stats = self::$ably->stats([ |
| 99 | "direction" => "forwards", |
| 100 | "start" => self::$timestampMs, |
| 101 | "end" => self::$timestampMs |
| 102 | ]); |
| 103 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 104 | $this->assertEquals( 50, $stats->items[0]->inbound->all->all->count, "Expected 50 messages" ); |
| 105 | |
| 106 | $stats = self::$ably->stats([ |
| 107 | "direction" => "forwards", |
| 108 | "start" => self::$timestampMs + $oneMinuteMs, |
| 109 | "end" => self::$timestampMs + $oneMinuteMs |
| 110 | ]); |
| 111 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 112 | $this->assertEquals( 60, $stats->items[0]->inbound->all->all->count, "Expected 60 messages" ); |
| 113 | |
| 114 | $stats = self::$ably->stats([ |
| 115 | "direction" => "forwards", |
| 116 | "start" => self::$timestampMs + $twoMinutesMs, |
| 117 | "end" => self::$timestampMs + $twoMinutesMs |
| 118 | ]); |
| 119 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 120 | $this->assertEquals( 70, $stats->items[0]->inbound->all->all->count, "Expected 70 messages" ); |
| 121 | } |
| 122 | |
| 123 | /** |
| 124 | * Check minute-level stats exist (backwards) |
| 125 | */ |
| 126 | public function testAppstatsMinute1() { |
| 127 | $oneMinuteMs = 60 * 1000; |
| 128 | $twoMinutesMs = 120 * 1000; |
| 129 | // get the stats for this channel |
| 130 | // note that bounds are inclusive |
| 131 | $stats = self::$ably->stats([ |
| 132 | "direction" => "backwards", |
| 133 | "start" => self::$timestampMs, |
| 134 | "end" => self::$timestampMs |
| 135 | ]); |
| 136 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 137 | $this->assertEquals( 50, $stats->items[0]->inbound->all->all->count, "Expected 50 messages" ); |
| 138 | |
| 139 | $stats = self::$ably->stats([ |
| 140 | "direction" => "backwards", |
| 141 | "start" => self::$timestampMs + $oneMinuteMs, |
| 142 | "end" => self::$timestampMs + $oneMinuteMs |
| 143 | ]); |
| 144 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 145 | $this->assertEquals( 60, $stats->items[0]->inbound->all->all->count, "Expected 60 messages" ); |
| 146 | |
| 147 | $stats = self::$ably->stats([ |
| 148 | "direction" => "backwards", |
| 149 | "start" => self::$timestampMs + $twoMinutesMs, |
| 150 | "end" => self::$timestampMs + $twoMinutesMs |
| 151 | ]); |
| 152 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 153 | $this->assertEquals( 70, $stats->items[0]->inbound->all->all->count, "Expected 70 messages" ); |
| 154 | } |
| 155 | |
| 156 | /** |
| 157 | * Check hour-level stats exist (forwards) |
| 158 | */ |
| 159 | public function testAppstatsHour0() { |
| 160 | $twoMinutesMs = 120 * 1000; |
| 161 | $stats = self::$ably->stats([ |
| 162 | "direction" => "forwards", |
| 163 | "start" => self::$timestampMs, |
| 164 | "end" => self::$timestampMs + $twoMinutesMs, |
| 165 | "unit" => "hour" |
| 166 | ]); |
| 167 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 168 | $this->assertEquals( 180, $stats->items[0]->inbound->all->all->count, "Expected 180 messages" ); |
| 169 | } |
| 170 | |
| 171 | /** |
| 172 | * Check day-level stats exist (forwards) |
| 173 | */ |
| 174 | public function testAppstatsDay0() { |
| 175 | $twoMinutesMs = 120 * 1000; |
| 176 | $stats = self::$ably->stats([ |
| 177 | "direction" => "forwards", |
| 178 | "start" => self::$timestampMs, |
| 179 | "end" => self::$timestampMs + $twoMinutesMs, |
| 180 | "unit" => "day" |
| 181 | ]); |
| 182 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 183 | $this->assertEquals( 180, $stats->items[0]->inbound->all->all->count, "Expected 180 messages" ); |
| 184 | } |
| 185 | |
| 186 | /** |
| 187 | * Check month-level stats exist (forwards) |
| 188 | */ |
| 189 | public function testAppstatsMonth0() { |
| 190 | $twoMinutesMs = 120 * 1000; |
| 191 | $stats = self::$ably->stats([ |
| 192 | "direction" => "forwards", |
| 193 | "start" => self::$timestampMs, |
| 194 | "end" => self::$timestampMs + $twoMinutesMs, |
| 195 | "unit" => "month" |
| 196 | ]); |
| 197 | |
| 198 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 199 | $this->assertEquals( 180, $stats->items[0]->inbound->all->all->count, "Expected 180 messages" ); |
| 200 | } |
| 201 | |
| 202 | /** |
| 203 | * Publish events and check limit query param (backwards) |
| 204 | */ |
| 205 | public function testAppstatsLimit0() { |
| 206 | $twoMinutesMs = 120 * 1000; |
| 207 | $stats = self::$ably->stats([ |
| 208 | "direction" => "backwards", |
| 209 | "start" => self::$timestampMs, |
| 210 | "end" => self::$timestampMs + $twoMinutesMs, |
| 211 | "limit" => 1 |
| 212 | ]); |
| 213 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 214 | $this->assertEquals( 70, $stats->items[0]->inbound->all->all->count, "Expected 70 messages" ); |
| 215 | } |
| 216 | |
| 217 | /** |
| 218 | * Check limit query param (forwards) |
| 219 | */ |
| 220 | public function testAppstatsLimit1() { |
| 221 | $twoMinutesMs = 120 * 1000; |
| 222 | $stats = self::$ably->stats([ |
| 223 | "direction" => "forwards", |
| 224 | "start" => self::$timestampMs, |
| 225 | "end" => self::$timestampMs + $twoMinutesMs, |
| 226 | "limit" => 1 |
| 227 | ]); |
| 228 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 229 | $this->assertEquals( 50, $stats->items[0]->inbound->all->all->count, "Expected 50 messages" ); |
| 230 | } |
| 231 | |
| 232 | /** |
| 233 | * Check query pagination (backwards) |
| 234 | */ |
| 235 | public function testAppstatsPagination0() { |
| 236 | $twoMinutesMs = 120 * 1000; |
| 237 | $stats = self::$ably->stats([ |
| 238 | "direction" => "backwards", |
| 239 | "start" => self::$timestampMs, |
| 240 | "end" => self::$timestampMs + $twoMinutesMs, |
| 241 | "limit" => 1 |
| 242 | ]); |
| 243 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 244 | $this->assertEquals( 70, $stats->items[0]->inbound->all->all->count, "Expected 70 messages" ); |
| 245 | // get next page |
| 246 | $stats = $stats->next(); |
| 247 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 248 | $this->assertEquals( 60, $stats->items[0]->inbound->all->all->count, "Expected 60 messages" ); |
| 249 | // get next page |
| 250 | $stats = $stats->next(); |
| 251 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 252 | $this->assertEquals( 50, $stats->items[0]->inbound->all->all->count, "Expected 50 messages" ); |
| 253 | // verify that there is no next page |
| 254 | $this->assertFalse( $stats->hasNext(), "Expected not to have next page" ); |
| 255 | $this->assertNull( $stats->next(), "Expected null next page" ); |
| 256 | } |
| 257 | |
| 258 | /** |
| 259 | * Check query pagination (forwards) |
| 260 | */ |
| 261 | public function testAppstatsPagination1() { |
| 262 | $twoMinutesMs = 120 * 1000; |
| 263 | $stats = self::$ably->stats([ |
| 264 | "direction" => "forwards", |
| 265 | "start" => self::$timestampMs, |
| 266 | "end" => self::$timestampMs + $twoMinutesMs, |
| 267 | "limit" => 1 |
| 268 | ]); |
| 269 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 270 | $this->assertEquals( 50, $stats->items[0]->inbound->all->all->count, "Expected 50 messages" ); |
| 271 | // get next page |
| 272 | $stats = $stats->next(); |
| 273 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 274 | $this->assertEquals( 60, $stats->items[0]->inbound->all->all->count, "Expected 60 messages" ); |
| 275 | // get next page |
| 276 | $stats = $stats->next(); |
| 277 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 278 | $this->assertEquals( 70, $stats->items[0]->inbound->all->all->count, "Expected 70 messages" ); |
| 279 | // verify that there is no next page |
| 280 | $this->assertFalse( $stats->hasNext(), "Expected not to have next page" ); |
| 281 | $this->assertNull( $stats->next(), "Expected null next page" ); |
| 282 | } |
| 283 | |
| 284 | /** |
| 285 | * Check query pagination rel="first" (backwards) |
| 286 | */ |
| 287 | public function testAppstatsPagination2() { |
| 288 | $twoMinutesMs = 120 * 1000; |
| 289 | $stats = self::$ably->stats([ |
| 290 | "direction" => "backwards", |
| 291 | "start" => self::$timestampMs, |
| 292 | "end" => self::$timestampMs + $twoMinutesMs, |
| 293 | "limit" => 1 |
| 294 | ]); |
| 295 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 296 | $this->assertEquals( 70, $stats->items[0]->inbound->all->all->count, "Expected 70 messages" ); |
| 297 | // get next page |
| 298 | $stats = $stats->next(); |
| 299 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 300 | $this->assertEquals( 60, $stats->items[0]->inbound->all->all->count, "Expected 60 messages" ); |
| 301 | // get first page |
| 302 | $stats = $stats->first(); |
| 303 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 304 | $this->assertEquals( 70, $stats->items[0]->inbound->all->all->count, "Expected 70 messages" ); |
| 305 | } |
| 306 | |
| 307 | /** |
| 308 | * Check query pagination rel="first" (forwards) |
| 309 | */ |
| 310 | public function testAppstatsPagination3() { |
| 311 | $twoMinutesMs = 120 * 1000; |
| 312 | $stats = self::$ably->stats([ |
| 313 | "direction" => "forwards", |
| 314 | "start" => self::$timestampMs, |
| 315 | "end" => self::$timestampMs + $twoMinutesMs, |
| 316 | "limit" => 1 |
| 317 | ]); |
| 318 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 319 | $this->assertEquals( 50, $stats->items[0]->inbound->all->all->count, "Expected 50 messages" ); |
| 320 | // get next page |
| 321 | $stats = $stats->next(); |
| 322 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 323 | $this->assertEquals( 60, $stats->items[0]->inbound->all->all->count, "Expected 60 messages" ); |
| 324 | // get first page |
| 325 | $stats = $stats->first(); |
| 326 | $this->assertEquals( 1, count( $stats->items ), "Expected 1 record" ); |
| 327 | $this->assertEquals( 50, $stats->items[0]->inbound->all->all->count, "Expected 50 messages" ); |
| 328 | } |
| 329 | |
| 330 | /** |
| 331 | * Verify default pagination limit (100), direction (backwards) and unit (minute) |
| 332 | */ |
| 333 | public function testPaginationDefaults () { |
| 334 | $twoHoursMs = 120 * 60 * 1000; |
| 335 | $stats = self::$ably->stats([ |
| 336 | "start" => self::$timestampOlderMs, |
| 337 | "end" => self::$timestampOlderMs + $twoHoursMs, |
| 338 | ]); |
| 339 | $this->assertEquals( 100, count( $stats->items ), "Expected 100 records" ); |
| 340 | |
| 341 | // verify order |
| 342 | $actualRecordsPeakData = []; |
| 343 | foreach ($stats->items as $minute) { |
| 344 | $actualRecordsPeakData[] = (int) $minute->channels->peak; |
| 345 | } |
| 346 | $expectedData = range( 101, 2, -1 ); |
| 347 | $this->assertEquals( $expectedData, $actualRecordsPeakData, 'Expected records in backward order' ); |
| 348 | } |
| 349 | } |