Cache::forget('server-market')); /** One offer in the feed's own shape. */ function offer(array $overrides = []): array { return array_merge([ 'cpu' => 'Ryzen 5 3600', 'ram_size' => 64, 'is_ecc' => true, 'hdd_hr' => ['2x SSD M.2 NVMe 1 TB'], 'serverDiskData' => ['nvme' => [1024, 1024], 'sata' => [], 'hdd' => []], 'datacenter' => 'FSN1-DC1', 'price' => 42.0, ], $overrides); } it('counts a mirrored pair once, not twice', function () { // A machine's usable space is not the sum of its disks on a platform whose // whole promise is "your data survives a disk dying". Http::fake(['*' => Http::response(['server' => [offer()]])]); expect(app(ServerMarket::class)->offers(500)[0]['flash_gb'])->toBe(1024); }); it('leaves out machines that could not take the largest parked order', function () { // 1.25× the largest single package: the mirror plus the host's own // footprint. An offer that only just fits is not an offer. Http::fake(['*' => Http::response(['server' => [offer()]])]); expect(app(ServerMarket::class)->offers(900))->toBe([]); }); it('leaves out spinning disks and non-ECC memory', function () { // Both are product decisions, not preferences: one VM per customer puts // every database on the same disks, and ECC is part of what the nightly // backup promise rests on. Http::fake(['*' => Http::response(['server' => [ offer(['is_ecc' => false]), offer(['serverDiskData' => ['nvme' => [], 'sata' => [], 'hdd' => [4096, 4096]]]), offer(['ram_size' => 16]), ]])]); expect(app(ServerMarket::class)->offers(100))->toBe([]); }); it('lists the cheapest first', function () { Http::fake(['*' => Http::response(['server' => [ offer(['price' => 80.0]), offer(['price' => 30.0]), offer(['price' => 55.0]), ]])]); expect(collect(app(ServerMarket::class)->offers(100))->pluck('price')->all()) ->toBe([30.0, 55.0, 80.0]); }); it('reads the disk description the feed actually sends', function () { // The feed sends a LIST of disk descriptions, not a string. Casting that to // string printed the word "Array" into the console and raised a warning // that took the whole page down with it. Http::fake(['*' => Http::response(['server' => [offer(['hdd_hr' => ['2x SSD M.2 NVMe 1 TB']])]])]); expect(app(ServerMarket::class)->offers(100)[0]['disks'])->toBe('2x SSD M.2 NVMe 1 TB'); }); it('says nothing rather than failing when the list cannot be reached', function () { // An outside list being down is not a reason for the capacity page to fail. // It shows the queue either way; the prices are the convenience. Http::fake(['*' => fn () => throw new RuntimeException('connection refused')]); expect(app(ServerMarket::class)->offers(100))->toBe([]); }); it('asks the provider once per quarter hour, not once per page view', function () { Http::fake(['*' => Http::response(['server' => [offer()]])]); app(ServerMarket::class)->offers(100); app(ServerMarket::class)->offers(100); app(ServerMarket::class)->offers(100); Http::assertSentCount(1); });