diff options
Diffstat (limited to 'src/lib/dns/tests/rdata_caa_unittest.cc')
-rw-r--r-- | src/lib/dns/tests/rdata_caa_unittest.cc | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/src/lib/dns/tests/rdata_caa_unittest.cc b/src/lib/dns/tests/rdata_caa_unittest.cc new file mode 100644 index 0000000..48b9076 --- /dev/null +++ b/src/lib/dns/tests/rdata_caa_unittest.cc @@ -0,0 +1,322 @@ +// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <algorithm> +#include <string> + +#include <util/buffer.h> +#include <dns/messagerenderer.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/rrclass.h> +#include <dns/rrtype.h> + +#include <gtest/gtest.h> + +#include <dns/tests/unittest_util.h> +#include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> + +#include <boost/algorithm/string.hpp> + +using namespace std; +using namespace isc; +using namespace isc::dns; +using namespace isc::util; +using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; + +namespace { +class Rdata_CAA_Test : public RdataTest { +protected: + Rdata_CAA_Test() : + caa_txt("0 issue \"ca.example.net\""), + rdata_caa(caa_txt) + {} + + void checkFromText_None(const string& rdata_str) { + checkFromText<generic::CAA, isc::Exception, isc::Exception>( + rdata_str, rdata_caa, false, false); + } + + void checkFromText_InvalidText(const string& rdata_str) { + checkFromText<generic::CAA, InvalidRdataText, InvalidRdataText>( + rdata_str, rdata_caa, true, true); + } + + void checkFromText_LexerError(const string& rdata_str) { + checkFromText + <generic::CAA, InvalidRdataText, MasterLexer::LexerError>( + rdata_str, rdata_caa, true, true); + } + + void checkFromText_BadString(const string& rdata_str) { + checkFromText + <generic::CAA, InvalidRdataText, isc::Exception>( + rdata_str, rdata_caa, true, false); + } + + const string caa_txt; + const generic::CAA rdata_caa; +}; + +const uint8_t rdata_caa_wiredata[] = { + // flags + 0x00, + // tag length + 0x5, + // tag + 'i', 's', 's', 'u', 'e', + // value + 'c', 'a', '.', 'e', 'x', 'a', 'm', 'p', 'l', 'e', + '.', 'n', 'e', 't' +}; + +TEST_F(Rdata_CAA_Test, createFromText) { + // Basic test + checkFromText_None(caa_txt); + + // With different spacing + checkFromText_None("0 issue \"ca.example.net\""); + + // Combination of lowercase and uppercase + checkFromText_None("0 IssUE \"ca.example.net\""); + + // string constructor throws if there's extra text, + // but lexer constructor doesn't + checkFromText_BadString(caa_txt + "\n" + caa_txt); + + // Missing value field + EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 issue")); +} + +TEST_F(Rdata_CAA_Test, fields) { + // Some of these may not be RFC conformant, but we relax the check + // in our code to work with other field values that may show up in + // the future. + EXPECT_NO_THROW(const generic::CAA rdata_caa2("1 issue \"ca.example.net\"")); + EXPECT_NO_THROW(const generic::CAA rdata_caa2("2 issue \"ca.example.net\"")); + EXPECT_NO_THROW(const generic::CAA rdata_caa2("3 issue \"ca.example.net\"")); + EXPECT_NO_THROW(const generic::CAA rdata_caa2("128 issue \"ca.example.net\"")); + EXPECT_NO_THROW(const generic::CAA rdata_caa2("255 issue \"ca.example.net\"")); + + EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 foo \"ca.example.net\"")); + EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 bar \"ca.example.net\"")); + EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 12345 \"ca.example.net\"")); + EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 w0x1y2z3 \"ca.example.net\"")); + EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 relaxed-too \"ca.example.net\"")); + EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 RELAXED.too \"ca.example.net\"")); + + // No value (this is redundant to the last test case in the + // .createFromText test + EXPECT_NO_THROW(const generic::CAA rdata_caa2("0 issue")); + + // > 255 would be broken + EXPECT_THROW(const generic::CAA rdata_caa2("256 issue \"ca.example.net\""), + InvalidRdataText); + + // Missing tag causes the value to be parsed as the tag field. As + // the tag field does not allow quoted strings, this throws. + EXPECT_THROW(const generic::CAA rdata_caa2("0 \"ca.example.net\""), + InvalidRdataText); + + // Tag is too long + const std::string tag(256, 'a'); + const std::string rdata_txt("0 " + tag + " \"ca.example.net\""); + EXPECT_THROW(const generic::CAA rdata_caa2(rdata_txt), InvalidRdataText); +} + +TEST_F(Rdata_CAA_Test, characterStringValue) { + const generic::CAA rdata_caa_unquoted("0 issue ca.example.net"); + EXPECT_EQ(0, rdata_caa_unquoted.compare(rdata_caa)); + + const generic::CAA rdata_caa_escape_X("0 issue ca.e\\xample.net"); + EXPECT_EQ(0, rdata_caa_escape_X.compare(rdata_caa)); + + const generic::CAA rdata_caa_escape_DDD("0 issue ca.e\\120ample.net"); + EXPECT_EQ(0, rdata_caa_escape_DDD.compare(rdata_caa)); + + const generic::CAA rdata_caa_multiline("0 issue (\nca.example.net)"); + EXPECT_EQ(0, rdata_caa_multiline.compare(rdata_caa)); +} + +TEST_F(Rdata_CAA_Test, badText) { + checkFromText_LexerError("0"); + checkFromText_LexerError("ZERO issue \"ca.example.net\""); + EXPECT_THROW(const generic::CAA rdata_caa2(caa_txt + " extra text"), + InvalidRdataText); + + // Yes, this is redundant to the last test cases in the .fields test + checkFromText_InvalidText("2345 issue \"ca.example.net\""); + + // negative values are trapped in the lexer rather than the + // constructor + checkFromText_LexerError("-2 issue \"ca.example.net\""); +} + +TEST_F(Rdata_CAA_Test, copyAndAssign) { + // Copy construct + generic::CAA rdata_caa2(rdata_caa); + EXPECT_EQ(0, rdata_caa.compare(rdata_caa2)); + + // Assignment, mainly to confirm it doesn't cause disruption. + rdata_caa2 = rdata_caa; + EXPECT_EQ(0, rdata_caa.compare(rdata_caa2)); +} + +TEST_F(Rdata_CAA_Test, createFromWire) { + // Basic test + EXPECT_EQ(0, rdata_caa.compare( + *rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), + "rdata_caa_fromWire1.wire"))); + + // Combination of lowercase and uppercase + EXPECT_EQ(0, rdata_caa.compare( + *rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), + "rdata_caa_fromWire2.wire"))); + + // Value field is empty + EXPECT_NO_THROW(rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), + "rdata_caa_fromWire3.wire")); + + // Tag field is empty + EXPECT_THROW(rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), + "rdata_caa_fromWire4.wire"), + InvalidRdataText); + + // Value field is shorter than rdata len + EXPECT_THROW(rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), + "rdata_caa_fromWire5"), + InvalidBufferPosition); + + // all RDATA is missing + EXPECT_THROW(rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), + "rdata_caa_fromWire6"), + InvalidBufferPosition); +} + +TEST_F(Rdata_CAA_Test, createFromParams) { + const generic::CAA rdata_caa2(0, "issue", "ca.example.net"); + EXPECT_EQ(0, rdata_caa2.compare(rdata_caa)); + + const generic::CAA rdata_caa4(0, "issue", "ca.e\\xample.net"); + EXPECT_EQ(0, rdata_caa4.compare(rdata_caa)); + + const generic::CAA rdata_caa5(0, "issue", "ca.e\\120ample.net"); + EXPECT_EQ(0, rdata_caa5.compare(rdata_caa)); + + // Tag is empty + EXPECT_THROW(const generic::CAA rdata_caa3(0, "", "ca.example.net"), + isc::InvalidParameter); + + // Tag is too long + const std::string tag(256, 'a'); + EXPECT_THROW(const generic::CAA rdata_caa3(0, tag, "ca.example.net"), + isc::InvalidParameter); + + // Value is too long + const std::string value(65536, 'a'); + EXPECT_THROW(const generic::CAA rdata_caa3(0, "issue", value), + InvalidRdataLength); +} + +TEST_F(Rdata_CAA_Test, toText) { + EXPECT_TRUE(boost::iequals(caa_txt, rdata_caa.toText())); + + const string caa_txt2("1 issue \"\""); + const generic::CAA rdata_caa2(caa_txt2); + EXPECT_TRUE(boost::iequals(caa_txt2, rdata_caa2.toText())); +} + +TEST_F(Rdata_CAA_Test, toWire) { + obuffer.clear(); + rdata_caa.toWire(obuffer); + + matchWireData(rdata_caa_wiredata, sizeof(rdata_caa_wiredata), + obuffer.getData(), obuffer.getLength()); +} + +TEST_F(Rdata_CAA_Test, compare) { + // Equality test is repeated from createFromWire tests above. + EXPECT_EQ(0, rdata_caa.compare( + *rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), + "rdata_caa_fromWire1.wire"))); + + const generic::CAA rdata_caa2("1 issue \"ca.example.net\""); + + EXPECT_EQ(1, rdata_caa2.compare(rdata_caa)); + EXPECT_EQ(-1, rdata_caa.compare(rdata_caa2)); +} + +TEST_F(Rdata_CAA_Test, getFlags) { + EXPECT_EQ(0, rdata_caa.getFlags()); +} + +TEST_F(Rdata_CAA_Test, getTag) { + EXPECT_EQ("issue", rdata_caa.getTag()); +} + +TEST_F(Rdata_CAA_Test, getValue) { + const uint8_t value_data[] = { + 'c', 'a', '.', + 'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', + 'n', 'e', 't' + }; + + const std::vector<uint8_t>& value = rdata_caa.getValue(); + matchWireData(value_data, sizeof(value_data), + &value[0], value.size()); +} + +TEST_F(Rdata_CAA_Test, emptyValueFromWire) { + const uint8_t rdf_wiredata[] = { + // flags + 0x00, + // tag length + 0x5, + // tag + 'i', 's', 's', 'u', 'e' + }; + + const generic::CAA rdf = + dynamic_cast<const generic::CAA&> + (*rdataFactoryFromFile(RRType("CAA"), RRClass("IN"), + "rdata_caa_fromWire3.wire")); + + EXPECT_EQ(0, rdf.getFlags()); + EXPECT_EQ("issue", rdf.getTag()); + + obuffer.clear(); + rdf.toWire(obuffer); + + matchWireData(rdf_wiredata, sizeof(rdf_wiredata), + obuffer.getData(), obuffer.getLength()); +} + +TEST_F(Rdata_CAA_Test, emptyValueFromString) { + const generic::CAA rdata_caa2("0 issue"); + const uint8_t rdata_caa2_wiredata[] = { + // flags + 0x00, + // tag length + 0x5, + // tag + 'i', 's', 's', 'u', 'e' + }; + + EXPECT_EQ(0, rdata_caa2.getFlags()); + EXPECT_EQ("issue", rdata_caa2.getTag()); + + obuffer.clear(); + rdata_caa2.toWire(obuffer); + + matchWireData(rdata_caa2_wiredata, sizeof(rdata_caa2_wiredata), + obuffer.getData(), obuffer.getLength()); +} +} |