Add tests

This commit is contained in:
Daniil Gentili 2019-06-11 16:40:22 +02:00
parent f5cbb3a9f5
commit e431e1014e
20 changed files with 759 additions and 141 deletions

View File

@ -17,7 +17,7 @@ $domains = \array_map(function ($line) {
\array_shift($domains);
// Set default resolver to DNS-over-HTTPS resolver
$DohConfig = new DoH\DoHConfig([new DoH\Nameserver('https://cloudflare-dns.com/dns-query')]);
$DohConfig = new DoH\DoHConfig([new DoH\Nameserver('https://mozilla.cloudflare-dns.com/dns-query')]);
Dns\resolver(new DoH\Rfc8484StubResolver($DohConfig));
Loop::run(function () use ($domains) {

View File

@ -24,7 +24,7 @@ $customConfigLoader = new class implements Dns\ConfigLoader {
};
// Set default resolver to DNS-over-https resolver
$DohConfig = new DoH\DoHConfig([new DoH\Nameserver('https://cloudflare-dns.com/dns-query')], null, null, $customConfigLoader);
$DohConfig = new DoH\DoHConfig([new DoH\Nameserver('https://mozilla.cloudflare-dns.com/dns-query')], null, null, $customConfigLoader);
Dns\resolver(new DoH\Rfc8484StubResolver($DohConfig));
Loop::run(function () {

View File

@ -0,0 +1,23 @@
<?php
require __DIR__ . "/_bootstrap.php";
use Amp\Dns;
use Amp\DoH;
use Amp\Loop;
use Amp\DoH\Nameserver;
// Set default resolver to DNS-over-https resolver
$DohConfig = new DoH\DoHConfig([new DoH\Nameserver('https://google.com/resolve', Nameserver::GOOGLE_JSON, ["Host" => "dns.google.com"])]);
Dns\resolver(new DoH\Rfc8484StubResolver($DohConfig));
Loop::run(function () {
$hostname = "amphp.org";
try {
pretty_print_records($hostname, yield Dns\resolve($hostname));
} catch (Dns\DnsException $e) {
pretty_print_error($hostname, $e);
}
});

View File

@ -7,7 +7,7 @@ use Amp\DoH;
use Amp\Loop;
// Set default resolver to DNS-over-HTTPS resolver
$DohConfig = new DoH\DoHConfig([new DoH\Nameserver('https://cloudflare-dns.com/dns-query')]);
$DohConfig = new DoH\DoHConfig([new DoH\Nameserver('https://mozilla.cloudflare-dns.com/dns-query')]);
Dns\resolver(new DoH\Rfc8484StubResolver($DohConfig));
Loop::run(function () {

View File

@ -11,6 +11,7 @@ use Amp\Dns\Resolver;
use Amp\Dns\UnixConfigLoader;
use Amp\Dns\WindowsConfigLoader;
use Amp\Dns\Rfc1035StubResolver;
use Amp\Dns\ConfigException;
final class DoHConfig
{
@ -29,10 +30,12 @@ final class DoHConfig
foreach ($nameservers as $nameserver) {
$this->validateNameserver($nameserver);
}
if ($resolver instanceof Rfc8484StubResolver) {
throw new ConfigException("Can't use Rfc8484StubResolver as subresolver for Rfc8484StubResolver");
}
$this->nameservers = $nameservers;
$this->artax = $artax ?? new DefaultClient();
$this->cache = $cache ?? new ArrayCache(5000/* default gc interval */, 256/* size */);
$this->configLoader = $configLoader ?? (\stripos(PHP_OS, "win") === 0
? new WindowsConfigLoader

View File

@ -62,7 +62,7 @@ final class HttpsSocket extends Socket
switch ($this->nameserver->getType()) {
case Nameserver::RFC8484_GET:
$data = $this->encoder->encode($message);
$request = (new Request($this->nameserver->getUri().'?'.http_build_query(['dns' => base64_encode($data), 'ct' => 'application/dns-message']), "GET"))
$request = (new Request($this->nameserver->getUri().'?'.\http_build_query(['dns' => \base64_encode($data), 'ct' => 'application/dns-message']), "GET"))
->withHeader('accept', 'application/dns-message')
->withHeaders($this->nameserver->getHeaders());
break;

View File

@ -23,6 +23,7 @@ use LibDNS\Records\Types\Type;
use LibDNS\Records\Types\TypeBuilder;
use LibDNS\Records\Types\Types;
use LibDNS\Messages\MessageTypes;
use Amp\Dns\DnsException;
/**
* Decodes JSON DNS strings to Message objects
@ -314,7 +315,15 @@ class JsonDecoder
*/
public function decode(string $result, int $requestId): Message
{
$result = json_decode($result, true);
$result = \json_decode($result, true);
if ($result === false) {
$error = \json_last_error_msg();
throw new DnsException("Could not decode JSON DNS payload ($error)");
}
if (!isset($result['Status'], $result['TC'], $result['RD'], $result['RA'])) {
throw new DnsException('Wrong reply from server, missing required fields');
}
$message = $this->messageFactory->create();
$decodingContext = $this->decodingContextFactory->create($this->packetFactory->create());

View File

@ -2,6 +2,9 @@
namespace Amp\DoH;
use Amp\Uri\InvalidDnsNameException;
use Amp\Dns\ConfigException;
final class Nameserver
{
const RFC8484_GET = 0;
@ -15,6 +18,12 @@ final class Nameserver
public function __construct(string $uri, int $type = self::RFC8484_POST, array $headers = [])
{
if (parse_url($uri, PHP_URL_SCHEME) !== 'https') {
throw new ConfigException('Did not provide a valid HTTPS url!');
}
if (!in_array($type, [self::RFC8484_GET, self::RFC8484_POST, self::GOOGLE_JSON], true)) {
throw new ConfigException('Invalid nameserver type provided!');
}
$this->uri = $uri;
$this->type = $type;
$this->headers = $headers;

View File

@ -1,4 +1,4 @@
<?php declare(strict_types=1);
<?php declare (strict_types = 1);
/**
* Encodes Message objects to raw network data
*
@ -13,7 +13,9 @@
*/
namespace Amp\DoH;
use Amp\Dns\DnsException;
use \LibDNS\Messages\Message;
use LibDNS\Messages\MessageTypes;
/**
* Encodes Message objects to raw network data
@ -32,12 +34,22 @@ class QueryEncoder
*/
public function encode(Message $message): string
{
return http_build_query([
'cd' => 0, // Do not disable result validation
'do' => 0, // Do not send me DNSSEC data
'type' => $message->getQuestionRecords()->getRecordByIndex(0)->getType(), // Record type being requested
'name' => implode('.', $message->getQuestionRecords()->getRecordByIndex(0)->getName()->getLabels()), // Record name being requested
'ct' => 'application/dns-json', // Content-type of request
]);
if ($message->getType() !== MessageTypes::QUERY) {
throw new DnsException('Invalid question: is not a question record');
}
$questions = $message->getQuestionRecords();
if ($questions->count() === 0) {
throw new DnsException('Invalid question: 0 question records provided');
}
$question = $questions->getRecordByIndex(0);
return \http_build_query(
[
'cd' => 0, // Do not disable result validation
'do' => 0, // Do not send me DNSSEC data
'type' => $question->getType(), // Record type being requested
'name' => implode('.', $question->getName()->getLabels()), // Record name being requested
'ct' => 'application/dns-json', // Content-type of request
]
);
}
}

View File

@ -1,23 +0,0 @@
<?php
namespace Amp\Dns\Test;
use Amp\PHPUnit\TestCase;
use LibDNS\Decoder\DecoderFactory;
use LibDNS\Messages\Message;
class DecodeTest extends TestCase
{
/**
* Regression test for https://github.com/amphp/dns/issues/53 and other reported issues.
*/
public function testDecodesEmptyDomains()
{
$message = \hex2bin("37ed818000010005000d000005676d61696c03636f6d00000f0001c00c000f000100000dff0020000a04616c74310d676d61696c2d736d74702d696e016c06676f6f676c65c012c00c000f000100000dff0009001404616c7432c02ec00c000f000100000dff0009002804616c7434c02ec00c000f000100000dff0009001e04616c7433c02ec00c000f000100000dff00040005c02e0000020001000026b50014016c0c726f6f742d73657276657273036e6574000000020001000026b500040163c0a30000020001000026b500040164c0a30000020001000026b50004016ac0a30000020001000026b500040162c0a30000020001000026b500040161c0a30000020001000026b500040167c0a30000020001000026b50004016bc0a30000020001000026b500040165c0a30000020001000026b50004016dc0a30000020001000026b500040169c0a30000020001000026b500040166c0a30000020001000026b500040168c0a3");
$decoder = (new DecoderFactory)->create();
$response = $decoder->decode($message);
$this->assertInstanceOf(Message::class, $response);
}
}

164
test/DoHConfigTest.php Normal file
View File

@ -0,0 +1,164 @@
<?php
namespace Amp\DoH\Test;
use Amp\Dns\Config;
use Amp\Dns\ConfigException;
use Amp\DoH\DoHConfig;
use Amp\DoH\Nameserver;
use Amp\PHPUnit\TestCase;
use Amp\Artax\DefaultClient;
use Amp\Dns\Rfc1035StubResolver;
use Amp\DoH\Rfc8484StubResolver;
use Amp\Cache\ArrayCache;
use Amp\Dns\WindowsConfigLoader;
use Amp\Dns\UnixConfigLoader;
class DoHConfigTest extends TestCase
{
/**
* @param string[] $nameservers Valid server array.
*
* @dataProvider provideValidServers
*/
public function testAcceptsValidServers(array $nameservers)
{
$this->assertInstanceOf(DoHConfig::class, new DoHConfig($nameservers));
}
public function provideValidServers()
{
return [
[[new Nameserver('https://cloudflare-dns.com/dns-query')]],
[[new Nameserver('https://cloudflare-dns.com/dns-query', Nameserver::RFC8484_POST)]],
[[new Nameserver('https://cloudflare-dns.com/dns-query', Nameserver::RFC8484_GET)]],
[[new Nameserver('https://cloudflare-dns.com/dns-query', Nameserver::GOOGLE_JSON)]],
[[new Nameserver('https://google.com/resolve', Nameserver::GOOGLE_JSON, ["host" => "dns.google.com"])]],
[[new Nameserver('https://cloudflare-dns.com/dns-query', Nameserver::GOOGLE_JSON), new Nameserver('https://google.com/resolve', Nameserver::GOOGLE_JSON, ["host" => "dns.google.com"])]],
];
}
/**
* @param string[] $nameservers Invalid server array.
*
* @dataProvider provideInvalidServers
*/
public function testRejectsInvalidServers(array $nameservers)
{
$this->expectException(ConfigException::class);
new DoHConfig($nameservers);
}
public function provideInvalidServers()
{
return [
[[]],
[[42]],
[[null]],
[[true]],
[["foobar"]],
[["foobar.com"]],
[["127.1.1:53"]],
[["127.1.1"]],
[["127.1.1.1.1"]],
[["126.0.0.5", "foobar"]],
[["42"]],
[["::1"]],
[["::1:53"]],
[["[::1]:53"]],
[["[::1]:"]],
[["[::1]:76235"]],
[["[::1]:0"]],
[["[::1]:-1"]],
[["[::1:51"]],
[["[::1]:abc"]],
];
}
/**
* @param \Amp\Artax\Client $client Valid artax instance
*
* @dataProvider provideValidArtax
*/
public function testAcceptsValidArtax($client)
{
$this->assertInstanceOf(DoHConfig::class, new DoHConfig([new Nameserver('https://cloudflare-dns.com/dns-query')], $client));
}
public function provideValidArtax()
{
return [
[new DefaultClient()]
[null]
];
}
/**
* @param \Amp\Dns\Resolver $resolver Valid resolver instance
*
* @dataProvider provideValidResolver
*/
public function testAcceptsValidResolver($resolver)
{
$this->assertInstanceOf(DoHConfig::class, new DoHConfig([new Nameserver('https://cloudflare-dns.com/dns-query')], null, $resolver));
}
public function provideValidResolver()
{
return [
[new Rfc1035StubResolver()]
[null]
];
}
/**
* @param $resolver any invalid resolver instance
*
* @dataProvider provideInvalidResolver
*/
public function testRejectsInvalidResolver($resolver)
{
$this->expectException(ConfigException::class);
new DoHConfig([new Nameserver('https://cloudflare-dns.com/dns-query')], null, $resolver);
}
public function provideInvalidResolver()
{
return [
[new Rfc8484StubResolver(new DoHConfig([new Nameserver('https://mozilla.cloudflare-dns.com/dns-query')]))]
];
}
/**
* @param $configLoader Valid ConfigLoader instance
*
* @dataProvider provideValidConfigLoader
*/
public function testAcceptsValidConfigLoader($configLoader)
{
$this->assertInstanceOf(DoHConfig::class, new DoHConfig([new Nameserver('https://cloudflare-dns.com/dns-query')], null, null, $configLoader));
}
public function provideValidConfigLoader()
{
return [
[new WindowsConfigLoader()]
[new UnixConfigLoader()]
[null]
];
}
/**
* @param \Amp\Cache\Cache Valid cache instance
*
* @dataProvider provideValidCache
*/
public function testAcceptsValidCache($cache)
{
$this->assertInstanceOf(DoHConfig::class, new DoHConfig([new Nameserver('https://cloudflare-dns.com/dns-query')], null, null, null, $cache));
}
public function provideValidCache()
{
return [
[new ArrayCache(5000/* default gc interval */, 256/* size */)]
[null]
];
}
}

View File

@ -1,43 +0,0 @@
<?php
namespace Amp\Dns\Test;
use Amp\Dns\HostLoader;
use Amp\Dns\Record;
use Amp\Loop;
use Amp\PHPUnit\TestCase;
class HostLoaderTest extends TestCase
{
public function testIgnoresCommentsAndParsesBasicEntry()
{
Loop::run(function () {
$loader = new HostLoader(__DIR__ . "/data/hosts");
$this->assertSame([
Record::A => [
"localhost" => "127.0.0.1",
],
], yield $loader->loadHosts());
});
}
public function testReturnsEmptyErrorOnFileNotFound()
{
Loop::run(function () {
$loader = new HostLoader(__DIR__ . "/data/hosts.not.found");
$this->assertSame([], yield $loader->loadHosts());
});
}
public function testIgnoresInvalidNames()
{
Loop::run(function () {
$loader = new HostLoader(__DIR__ . "/data/hosts.invalid.name");
$this->assertSame([
Record::A => [
"localhost" => "127.0.0.1",
],
], yield $loader->loadHosts());
});
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace Amp\Dns\Test;
use Amp\PHPUnit\TestCase;
use Amp\DoH\JsonDecoderFactory;
use Amp\DoH\JsonDecoder;
class JsonDecoderFactoryTest extends TestCase
{
public function testJsonDecoderFactoryWorks()
{
$this->assertInstanceOf(JsonDecoder::class, (new JsonDecoderFactory)->create());
}
}

201
test/JsonDecoderTest.php Normal file
View File

@ -0,0 +1,201 @@
<?php
namespace Amp\Dns\Test;
use Amp\DoH\JsonDecoderFactory;
use Amp\PHPUnit\TestCase;
use LibDNS\Messages\Message;
use Amp\Dns\DnsException;
use LibDNS\Messages\MessageTypes;
class JsonDecoderTest extends TestCase
{
/**
* Test decoding of valid JSON DNS payloads
*
* @param string $message
* @param int $requestId
* @return void
*
* @dataProvider provideValidJsonPayloads
*/
public function testDecodesValidJsonPayloads(string $message, int $requestId)
{
$decoder = (new JsonDecoderFactory)->create();
$response = $decoder->decode($message, $requestId);
$this->assertInstanceOf(Message::class, $response);
$this->assertEquals(MessageTypes::RESPONSE, $response->getType());
}
public function provideValidJsonPayloads()
{
return [
[
'{
"Status": 0,
"TC": false,
"RD": true,
"RA": true,
"AD": false,
"CD": false,
"Question":
[
{
"name": "apple.com.",
"type": 1
}
],
"Answer":
[
{
"name": "apple.com.",
"type": 1,
"TTL": 3599,
"data": "17.178.96.59"
},
{
"name": "apple.com.",
"type": 1,
"TTL": 3599,
"data": "17.172.224.47"
},
{
"name": "apple.com.",
"type": 1,
"TTL": 3599,
"data": "17.142.160.59"
}
],
"Additional": [ ],
"edns_client_subnet": "12.34.56.78/0"
}',
2,
],
[
'{"Status": 0,"TC": false,"RD": true, "RA": true, "AD": true,"CD": false,"Question":[{"name": "example.com.", "type": 28}],"Answer":[{"name": "example.com.", "type": 28, "TTL": 7092, "data": "2606:2800:220:1:248:1893:25c8:1946"}]}',
3,
],
[
'{"Status": 0,"TC": false,"RD": true, "RA": true, "AD": false,"CD": false,"Question":[{"name": "daniil.it.", "type": 1}],"Answer":[{"name": "daniil.it.", "type": 1, "TTL": 300, "data": "104.27.146.166"},{"name": "daniil.it.", "type": 1, "TTL": 300, "data": "104.27.147.166"}]}',
3,
],
[
'{"Status": 0,"TC": false,"RD": true, "RA": true, "AD": false,"CD": false,"Question":[{"name": "amphp.org.", "type": 15}],"Answer":[{"name": "amphp.org.", "type": 15, "TTL": 86400, "data": "0 mail.negativeion.net."}]}',
3,
],
];
}
/**
* Test decoding of invalid JSON DNS payloads
*
* @param string $message
* @param int $requestId
* @return void
*
* @dataProvider provideInvalidJsonPayloads
*/
public function testDecodesInvalidJsonPayloads($message, $requestId)
{
$decoder = (new JsonDecoderFactory)->create();
$this->expectException(DnsException::class);
$decoder->decode($message, $requestId);
}
public function provideInvalidJsonPayloads()
{
return [
[
'{lmfao
"Status": 0,
"TC": false,
"RD": true,
"RA": true,
"AD": false,
"CD": false,
"Question":
[
{
"name": "apple.com.",
"type": 1
}
],
"Answer":
[
{
"name": "apple.com.",
"type": 1,
"TTL": 3599,
"data": "17.178.96.59"
},
{
"name": "apple.com.",
"type": 1,
"TTL": 3599,
"data": "17.172.224.47"
},
{
"name": "apple.com.",
"type": 1,
"TTL": 3599,
"data": "17.142.160.59"
}
],
"Additional": [ ],
"edns_client_subnet": "12.34.56.78/0"
}',
2,
],
[
'xd{"Status": 0,"TC": false,"RD": true, "RA": true, "AD": true,"CD": false,"Question":[{"name": "example.com.", "type": 28}],"Answer":[{"name": "example.com.", "type": 28, "TTL": 7092, "data": "2606:2800:220:1:248:1893:25c8:1946"}]}',
3,
],
[
'whaaa{"Status": 0,"TC": false,"RD": true, "RA": true, "AD": false,"CD": false,"Question":[{"name": "daniil.it.", "type": 1}],"Answer":[{"name": "daniil.it.", "type": 1, "TTL": 300, "data": "104.27.146.166"},{"name": "daniil.it.", "type": 1, "TTL": 300, "data": "104.27.147.166"}]}',
3,
],
[
'xdxdxxxxx{"Status": 0,"TC": false,"RD": true, "RA": true, "AD": false,"CD": false,"Question":[{"name": "amphp.org.", "type": 15}],"Answer":[{"name": "amphp.org.", "type": 15, "TTL": 86400, "data": "0 mail.negativeion.net."}]}',
3,
],
[
'{"TC": false,"RD": true, "RA": true, "AD": false,"CD": false,"Question":[{"name": "amphp.org.", "type": 15}],"Answer":[{"name": "amphp.org.", "type": 15, "TTL": 86400, "data": "0 mail.negativeion.net."}]}',
3,
],
[
'{"Status": 0,"RD": true, "RA": true, "AD": false,"CD": false,"Question":[{"name": "amphp.org.", "type": 15}],"Answer":[{"name": "amphp.org.", "type": 15, "TTL": 86400, "data": "0 mail.negativeion.net."}]}',
3,
],
[
'{"Status": 0,"TC": false,"RA": true, "AD": false,"CD": false,"Question":[{"name": "amphp.org.", "type": 15}],"Answer":[{"name": "amphp.org.", "type": 15, "TTL": 86400, "data": "0 mail.negativeion.net."}]}',
3,
],
[
'{"Status": 0,"TC": false,"RD": true, "AD": false,"CD": false,"Question":[{"name": "amphp.org.", "type": 15}],"Answer":[{"name": "amphp.org.", "type": 15, "TTL": 86400, "data": "0 mail.negativeion.net."}]}',
3,
],
[
'xd',
0
],
[
null,
0
],
[
[],
0
],
[
0,
0
],
[
new class {},
0
]
];
}
}

86
test/NameserverTest.php Normal file
View File

@ -0,0 +1,86 @@
<?php
namespace Amp\DoH\Test;
use Amp\PHPUnit\TestCase;
use Amp\DoH\Nameserver;
class NameserverTest extends TestCase
{
/**
* @param string[] $nameservers Valid server array.
*
* @dataProvider provideValidServers
*/
public function testAcceptsValidServers($nameserver, $type = Nameserver::RFC8484_POST, $headers = [])
{
$this->assertInstanceOf(Nameserver::class, new Nameserver($nameserver, $type, $headers));
}
public function provideValidServers()
{
return [
['https://mozilla.cloudflare-dns.com/dns-query'],
['https://mozilla.cloudflare-dns.com/dns-query', Nameserver::RFC8484_POST],
['https://mozilla.cloudflare-dns.com/dns-query', Nameserver::RFC8484_GET],
['https://mozilla.cloudflare-dns.com/dns-query', Nameserver::GOOGLE_JSON],
['https://google.com/resolve', Nameserver::GOOGLE_JSON, ["Host" => "dns.google.com"]],
];
}
/**
* @param string[] $nameservers Invalid server array.
*
* @dataProvider provideInvalidServers
*/
public function testRejectsInvalidServers($nameserver, $type = Nameserver::RFC8484_POST, $headers = [])
{
$this->expectException(ConfigException::class);
new Nameserver($nameserver, $type, $headers);
}
public function provideInvalidServers()
{
return [
[''],
[42],
[null],
[true],
["foobar"],
["foobar.com"],
["127.1.1"],
["127.1.1.1.1"],
["126.0.0.5"],
["42"],
["::1"],
["::1:53"],
["[::1]:"],
["[::1]:76235"],
["[::1]:0"],
["[::1]:-1"],
["[::1:51"],
["[::1]:abc"],
['http://mozilla.cloudflare-dns.com/dns-query'],
['http://mozilla.cloudflare-dns.com/dns-query', Nameserver::RFC8484_POST],
['http://mozilla.cloudflare-dns.com/dns-query', Nameserver::RFC8484_GET],
['http://mozilla.cloudflare-dns.com/dns-query', Nameserver::GOOGLE_JSON],
['http://google.com/resolve', Nameserver::GOOGLE_JSON, ["Host" => "dns.google.com"]],
['mozilla.cloudflare-dns.com/dns-query'],
['mozilla.cloudflare-dns.com/dns-query', Nameserver::RFC8484_POST],
['mozilla.cloudflare-dns.com/dns-query', Nameserver::RFC8484_GET],
['mozilla.cloudflare-dns.com/dns-query', Nameserver::GOOGLE_JSON],
['google.com/resolve', Nameserver::GOOGLE_JSON, ["Host" => "dns.google.com"]],
['https://mozilla.cloudflare-dns.com/dns-query'],
['https://mozilla.cloudflare-dns.com/dns-query', 100],
['https://mozilla.cloudflare-dns.com/dns-query', "2"],
['https://mozilla.cloudflare-dns.com/dns-query', -1],
['https://mozilla.cloudflare-dns.com/dns-query', null],
['https://mozilla.cloudflare-dns.com/dns-query', "hi"],
['https://mozilla.cloudflare-dns.com/dns-query', "foobar"],
];
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace Amp\Dns\Test;
use Amp\PHPUnit\TestCase;
use Amp\DoH\QueryEncoderFactory;
use Amp\DoH\QueryEncoder;
class QueryEncoderFactoryTest extends TestCase
{
public function testQueryEncoderFactoryWorks()
{
$this->assertInstanceOf(QueryEncoder::class, (new QueryEncoderFactory)->create());
}
}

208
test/QueryEncoderTest.php Normal file
View File

@ -0,0 +1,208 @@
<?php
namespace Amp\Dns\Test;
use Amp\Dns\DnsException;
use Amp\DoH\JsonDecoderFactory;
use Amp\DoH\QueryEncoderFactory;
use Amp\PHPUnit\TestCase;
use LibDNS\Messages\Message;
use LibDNS\Messages\MessageTypes;
class QueryEncoderTest extends TestCase
{
/**
* Test encoding of valid DNS message payloads
*
* @param string $message
* @return void
*
* @dataProvider provideValidQueryPayloads
*/
public function testEncodesValidQueryPayloads(string $message)
{
$decoder = (new JsonDecoderFactory)->create();
$response = $decoder->decode($message, 0);
$response->setType(MessageTypes::QUERY);
$encoder = (new QueryEncoderFactory)->create();
$request = $encoder->encode($response);
$this->assertInternalType('string', $request, "Got a ".gettype($request)." instead of a string");
parse_str($request, $output);
$this->assertNotEmpty($output);
$this->assertArrayHasKey('cd', $output);
$this->assertArrayHasKey('do', $output);
$this->assertArrayHasKey('ct', $output);
$this->assertArrayHasKey('type', $output);
$this->assertArrayHasKey('name', $output);
$this->assertEquals($output['cd'], 0);
$this->assertEquals($output['do'], 0);
$this->assertEquals($output['ct'], 'application/dns-json');
$this->assertEquals($output['type'], $response->getQuestionRecords()->getRecordByIndex(0)->getType());
$this->assertEquals($output['name'], implode('.', $message->getQuestionRecords()->getRecordByIndex(0)->getName()->getLabels()));
}
public function provideValidJsonPayloads()
{
return [
[
'{
"Status": 0,
"TC": false,
"RD": true,
"RA": true,
"AD": false,
"CD": false,
"Question":
[
{
"name": "apple.com.",
"type": 1
}
],
"Answer":
[
{
"name": "apple.com.",
"type": 1,
"TTL": 3599,
"data": "17.178.96.59"
},
{
"name": "apple.com.",
"type": 1,
"TTL": 3599,
"data": "17.172.224.47"
},
{
"name": "apple.com.",
"type": 1,
"TTL": 3599,
"data": "17.142.160.59"
}
],
"Additional": [ ],
"edns_client_subnet": "12.34.56.78/0"
}',
2,
],
[
'{"Status": 0,"TC": false,"RD": true, "RA": true, "AD": true,"CD": false,"Question":[{"name": "example.com.", "type": 28}],"Answer":[{"name": "example.com.", "type": 28, "TTL": 7092, "data": "2606:2800:220:1:248:1893:25c8:1946"}]}',
3,
],
[
'{"Status": 0,"TC": false,"RD": true, "RA": true, "AD": false,"CD": false,"Question":[{"name": "daniil.it.", "type": 1}],"Answer":[{"name": "daniil.it.", "type": 1, "TTL": 300, "data": "104.27.146.166"},{"name": "daniil.it.", "type": 1, "TTL": 300, "data": "104.27.147.166"}]}',
3,
],
[
'{"Status": 0,"TC": false,"RD": true, "RA": true, "AD": false,"CD": false,"Question":[{"name": "amphp.org.", "type": 15}],"Answer":[{"name": "amphp.org.", "type": 15, "TTL": 86400, "data": "0 mail.negativeion.net."}]}',
3,
],
];
}
/**
* Test query encoding of invalid DNS payloads
*
* @param $request
* @return void
*
* @dataProvider provideInvalidQueryPayloads
*/
public function testEncodesInvalidQueryPayloads($request)
{
$encoder = (new QueryEncoderFactory)->create();
$this->expectException(DnsException::class);
$encoder->encode($request);
}
public function provideInvalidQueryPayloads()
{
$decoder = (new JsonDecoderFactory)->create();
return [
[
$decoder->decode(
'{
"Status": 0,
"TC": false,
"RD": true,
"RA": true,
"AD": false,
"CD": false,
"Question":
[
{
"name": "apple.com.",
"type": 1
}
],
"Answer":
[
{
"name": "apple.com.",
"type": 1,
"TTL": 3599,
"data": "17.178.96.59"
},
{
"name": "apple.com.",
"type": 1,
"TTL": 3599,
"data": "17.172.224.47"
},
{
"name": "apple.com.",
"type": 1,
"TTL": 3599,
"data": "17.142.160.59"
}
],
"Additional": [ ],
"edns_client_subnet": "12.34.56.78/0"
}',
2,
),
],
[
$decoder->decode(
'{
"Status": 0,
"TC": false,
"RD": true,
"RA": true,
"AD": false,
"CD": false,
"Question":
[
],
"Answer":
[
{
"name": "apple.com.",
"type": 1,
"TTL": 3599,
"data": "17.178.96.59"
},
{
"name": "apple.com.",
"type": 1,
"TTL": 3599,
"data": "17.172.224.47"
},
{
"name": "apple.com.",
"type": 1,
"TTL": 3599,
"data": "17.142.160.59"
}
],
"Additional": [ ],
"edns_client_subnet": "12.34.56.78/0"
}',
2,
),
],
];
}
}

View File

@ -1,27 +0,0 @@
<?php
namespace Amp\Dns\Test;
use Amp\Dns\Record;
use Amp\PHPUnit\TestCase;
class RecordTest extends TestCase
{
public function testGetName()
{
$this->assertSame("A", Record::getName(Record::A));
}
public function testGetNameOnInvalidRecordType()
{
$this->expectException(\Error::class);
$this->expectExceptionMessage("65536 does not correspond to a valid record type (must be between 0 and 65535).");
Record::getName(65536);
}
public function testGetNameOnUnknownRecordType()
{
$this->assertSame("unknown (1000)", Record::getName(1000));
}
}

View File

@ -1,34 +0,0 @@
<?php
namespace Amp\Dns\Test;
use Amp\Dns\Config;
use Amp\Dns\ConfigException;
use Amp\Dns\UnixConfigLoader;
use Amp\PHPUnit\TestCase;
use function Amp\Promise\wait;
class UnixConfigLoaderTest extends TestCase
{
public function test()
{
$loader = new UnixConfigLoader(__DIR__ . "/data/resolv.conf");
/** @var Config $result */
$result = wait($loader->loadConfig());
$this->assertSame([
"127.0.0.1:53",
"[2001:4860:4860::8888]:53",
], $result->getNameservers());
$this->assertSame(5000, $result->getTimeout());
$this->assertSame(3, $result->getAttempts());
}
public function testNoDefaultsOnConfNotFound()
{
$this->expectException(ConfigException::class);
wait((new UnixConfigLoader(__DIR__ . "/data/non-existent.conf"))->loadConfig());
}
}