Changeset View
Changeset View
Standalone View
Standalone View
src/seeder/test/seeder_tests.cpp
// Copyright (c) 2019 The Bitcoin developers | // Copyright (c) 2019 The Bitcoin developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#define BOOST_TEST_MODULE Bitcoin Seeder Test Suite | #define BOOST_TEST_MODULE Bitcoin Seeder Test Suite | ||||
#include <seeder/dns.h> | |||||
#include <string> | |||||
#include <vector> | |||||
#include <boost/test/unit_test.hpp> | #include <boost/test/unit_test.hpp> | ||||
BOOST_AUTO_TEST_SUITE(seeder_tests) | BOOST_AUTO_TEST_SUITE(seeder_tests) | ||||
BOOST_AUTO_TEST_CASE(test_stub) { | static const int MAX_QUERY_NAME_LENGTH = 255; | ||||
BOOST_CHECK_EQUAL(true, true); | // Max size of the null-terminated buffer parse_name() writes to. | ||||
static const int MAX_QUERY_NAME_BUFFER_LENGTH = MAX_QUERY_NAME_LENGTH + 1; | |||||
static const uint8_t END_OF_NAME_FIELD = 0; | |||||
static const size_t MAX_LABEL_LENGTH = 63; | |||||
// Builds the name field of the question section of a DNS query | |||||
static std::vector<uint8_t> | |||||
CreateDNSQuestionNameField(const std::string &queryName) { | |||||
std::vector<uint8_t> nameField; | |||||
size_t i = 0; | |||||
size_t labelIndex = 0; | |||||
while (i < queryName.size()) { | |||||
if (queryName[i] == '.') { | |||||
// Push the length of the label and then the label | |||||
nameField.push_back(i - labelIndex); | |||||
while (labelIndex < i) { | |||||
nameField.push_back(queryName[labelIndex]); | |||||
labelIndex++; | |||||
} | |||||
labelIndex = i + 1; | |||||
} | |||||
i++; | |||||
} | |||||
// Push the length of the label and then the label | |||||
nameField.push_back(i - labelIndex); | |||||
while (labelIndex < i) { | |||||
nameField.push_back(queryName[labelIndex]); | |||||
labelIndex++; | |||||
} | |||||
nameField.push_back(END_OF_NAME_FIELD); | |||||
return nameField; | |||||
} | |||||
static void CheckParseName(const std::string &queryName) { | |||||
std::vector<uint8_t> nameField = CreateDNSQuestionNameField(queryName); | |||||
// Name field input testing | |||||
jasonbcox: I see what you did where you test the passing cases in the next loop. If you keep it this way… | |||||
for (size_t nameFieldEndIndex = 0; nameFieldEndIndex < nameField.size(); | |||||
nameFieldEndIndex++) { | |||||
std::vector<char> parsedQueryName(MAX_QUERY_NAME_BUFFER_LENGTH, 0); | |||||
const uint8_t *nameFieldBegin = nameField.data(); | |||||
int ret = parse_name( | |||||
&nameFieldBegin, nameFieldBegin + nameFieldEndIndex, | |||||
nameField.data(), parsedQueryName.data(), parsedQueryName.size()); | |||||
BOOST_CHECK(ret != 0); | |||||
} | |||||
// Output buffer size testing | |||||
jasonbcoxUnsubmitted Not Done Inline ActionsRelated to above: // Test output buffer sizes with adequate name field length jasonbcox: Related to above: `// Test output buffer sizes with adequate name field length` | |||||
for (size_t outputBufferSize = 1; | |||||
outputBufferSize < MAX_QUERY_NAME_BUFFER_LENGTH; outputBufferSize++) { | |||||
std::vector<char> parsedQueryName(outputBufferSize, 0); | |||||
const uint8_t *nameFieldBegin = nameField.data(); | |||||
int ret = parse_name(&nameFieldBegin, nameFieldBegin + nameField.size(), | |||||
nameField.data(), parsedQueryName.data(), | |||||
parsedQueryName.size()); | |||||
if (outputBufferSize <= queryName.size()) { | |||||
BOOST_CHECK(ret != 0); | |||||
} else { | |||||
// Happy path | |||||
BOOST_CHECK(ret == 0); | |||||
BOOST_CHECK_EQUAL(parsedQueryName.data(), queryName); | |||||
} | |||||
} | |||||
} | |||||
static void CheckParseNameError( | |||||
const std::string &queryName, const int expectedError, | |||||
const size_t &outputBufferSize = MAX_QUERY_NAME_BUFFER_LENGTH) { | |||||
std::vector<uint8_t> nameField = CreateDNSQuestionNameField(queryName); | |||||
std::vector<char> parsedQueryName(outputBufferSize, 0); | |||||
const uint8_t *nameFieldBegin = nameField.data(); | |||||
int ret = parse_name(&nameFieldBegin, nameFieldBegin + nameField.size(), | |||||
nameField.data(), parsedQueryName.data(), | |||||
parsedQueryName.size()); | |||||
BOOST_CHECK_EQUAL(ret, expectedError); | |||||
} | |||||
BOOST_AUTO_TEST_CASE(parse_name_tests) { | |||||
CheckParseName("www.domain.com"); | |||||
CheckParseName("domain.com"); | |||||
// Shortest valid domain name is 1 char followed by the extension | |||||
CheckParseName("a.co"); | |||||
CheckParseName("sub1.sub2.domain.co.uk"); | |||||
CheckParseName("my-domain.com"); | |||||
// Check behavior for name with maximum length label | |||||
std::string maxLengthLabel; | |||||
for (size_t i = 0; i < MAX_LABEL_LENGTH; i++) { | |||||
maxLengthLabel += 'a'; | |||||
} | |||||
BOOST_CHECK_EQUAL(maxLengthLabel.size(), MAX_LABEL_LENGTH); | |||||
CheckParseName("www." + maxLengthLabel + ".com"); | |||||
// Check behavior for a name that is the maximum length | |||||
std::string maxLengthQName = maxLengthLabel + '.' + maxLengthLabel + '.' + | |||||
maxLengthLabel + '.' + maxLengthLabel; | |||||
BOOST_CHECK_EQUAL(maxLengthQName.size(), MAX_QUERY_NAME_LENGTH); | |||||
CheckParseName(maxLengthQName); | |||||
// Check that an oversized label causes an error | |||||
CheckParseNameError("www." + maxLengthLabel + "a.com", -1); | |||||
} | } | ||||
BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() |
I see what you did where you test the passing cases in the next loop. If you keep it this way, I think this comment is misleading. Should be something like // Test when name field is too short to reach null terminator