- Wrap return values in collect() to maintain Collection compatibility - Add comment explaining threshold <= 2 prevents division by zero - Refactor tests to use actual Server model method via reflection - Use seeded mt_rand() for reproducible test results 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
131 lines
3.3 KiB
PHP
131 lines
3.3 KiB
PHP
<?php
|
|
|
|
use App\Models\Server;
|
|
|
|
/**
|
|
* Helper to call the private downsampleLTTB method on Server model via reflection.
|
|
*/
|
|
function callDownsampleLTTB(array $data, int $threshold): array
|
|
{
|
|
$server = new Server;
|
|
$reflection = new ReflectionClass($server);
|
|
$method = $reflection->getMethod('downsampleLTTB');
|
|
|
|
return $method->invoke($server, $data, $threshold);
|
|
}
|
|
|
|
it('returns data unchanged when below threshold', function () {
|
|
$data = [
|
|
[1000, 10.5],
|
|
[2000, 20.3],
|
|
[3000, 15.7],
|
|
];
|
|
|
|
$result = callDownsampleLTTB($data, 1000);
|
|
|
|
expect($result)->toBe($data);
|
|
});
|
|
|
|
it('returns data unchanged when threshold is 2 or less', function () {
|
|
$data = [
|
|
[1000, 10.5],
|
|
[2000, 20.3],
|
|
[3000, 15.7],
|
|
[4000, 25.0],
|
|
[5000, 12.0],
|
|
];
|
|
|
|
$result = callDownsampleLTTB($data, 2);
|
|
expect($result)->toBe($data);
|
|
|
|
$result = callDownsampleLTTB($data, 1);
|
|
expect($result)->toBe($data);
|
|
});
|
|
|
|
it('downsamples to target threshold count', function () {
|
|
// Seed for reproducibility
|
|
mt_srand(42);
|
|
|
|
// Generate 100 data points
|
|
$data = [];
|
|
for ($i = 0; $i < 100; $i++) {
|
|
$data[] = [$i * 1000, mt_rand(0, 100) / 10];
|
|
}
|
|
|
|
$result = callDownsampleLTTB($data, 10);
|
|
|
|
expect(count($result))->toBe(10);
|
|
});
|
|
|
|
it('preserves first and last data points', function () {
|
|
$data = [];
|
|
for ($i = 0; $i < 100; $i++) {
|
|
$data[] = [$i * 1000, $i * 1.5];
|
|
}
|
|
|
|
$result = callDownsampleLTTB($data, 20);
|
|
|
|
// First point should be preserved
|
|
expect($result[0])->toBe($data[0]);
|
|
|
|
// Last point should be preserved
|
|
expect(end($result))->toBe(end($data));
|
|
});
|
|
|
|
it('maintains chronological order', function () {
|
|
$data = [];
|
|
for ($i = 0; $i < 500; $i++) {
|
|
$data[] = [$i * 60000, sin($i / 10) * 50 + 50]; // Sine wave pattern
|
|
}
|
|
|
|
$result = callDownsampleLTTB($data, 50);
|
|
|
|
// Verify all timestamps are in non-decreasing order
|
|
$previousTimestamp = -1;
|
|
foreach ($result as $point) {
|
|
expect($point[0])->toBeGreaterThanOrEqual($previousTimestamp);
|
|
$previousTimestamp = $point[0];
|
|
}
|
|
});
|
|
|
|
it('handles large datasets efficiently', function () {
|
|
// Seed for reproducibility
|
|
mt_srand(123);
|
|
|
|
// Simulate 30 days of data at 5-second intervals (518,400 points)
|
|
// For test purposes, use 10,000 points
|
|
$data = [];
|
|
for ($i = 0; $i < 10000; $i++) {
|
|
$data[] = [$i * 5000, mt_rand(0, 100)];
|
|
}
|
|
|
|
$startTime = microtime(true);
|
|
$result = callDownsampleLTTB($data, 1000);
|
|
$executionTime = microtime(true) - $startTime;
|
|
|
|
expect(count($result))->toBe(1000);
|
|
expect($executionTime)->toBeLessThan(1.0); // Should complete in under 1 second
|
|
});
|
|
|
|
it('preserves peaks and valleys in data', function () {
|
|
// Create data with clear peaks and valleys
|
|
$data = [];
|
|
for ($i = 0; $i < 100; $i++) {
|
|
if ($i === 25) {
|
|
$value = 100; // Peak
|
|
} elseif ($i === 75) {
|
|
$value = 0; // Valley
|
|
} else {
|
|
$value = 50;
|
|
}
|
|
$data[] = [$i * 1000, $value];
|
|
}
|
|
|
|
$result = callDownsampleLTTB($data, 20);
|
|
|
|
// The peak (100) and valley (0) should be preserved due to LTTB algorithm
|
|
$values = array_column($result, 1);
|
|
|
|
expect(in_array(100, $values))->toBeTrue();
|
|
expect(in_array(0, $values))->toBeTrue();
|
|
});
|