Http::response([ [ 'urls' => 'stun:stun.relay.metered.ca:80', ], [ 'urls' => 'turn:standard.relay.metered.ca:80', 'username' => 'metered_usr', 'credential' => 'metered_pwd', ], ], 200), ]); $provider = new MeteredIceCandidateProvider([ 'url' => $mockUrl, 'key' => $apiKey, 'timeout' => 3, 'cache_ttl' => 60, ]); $candidates = $provider->getIceCandidates(); $this->assertCount(2, $candidates); $array = $candidates->toArray(); $this->assertEquals('stun:stun.relay.metered.ca:80', $array[0]['urls']); $this->assertEquals('metered_usr', $array[1]['username']); $this->assertEquals('metered_pwd', $array[1]['credential']); // Verify result is cached (subsequent call does not hit HTTP) Http::fake([ $mockUrl.'*' => Http::response([], 500), ]); $cachedCandidates = $provider->getIceCandidates(); $this->assertCount(2, $cachedCandidates); } public function test_throws_exception_on_metered_http_error(): void { $mockUrl = 'https://mock.metered.live/api/v1/turn/credentials'; Http::fake([ $mockUrl.'*' => Http::response('Server Error', 500), ]); $provider = new MeteredIceCandidateProvider([ 'url' => $mockUrl, 'key' => 'key', ]); $this->expectException(RuntimeException::class); $this->expectExceptionMessage('Metered API Error: 500'); $provider->getIceCandidates(); } }