tests: sync common testing infrastructure with ndn-cxx
Also upgrade waf to version 2.0.21
Change-Id: Ifad909ca2f3463796d928b62f3131418b654446f
diff --git a/tests/unit/encryptor.t.cpp b/tests/unit/encryptor.t.cpp
new file mode 100644
index 0000000..147c663
--- /dev/null
+++ b/tests/unit/encryptor.t.cpp
@@ -0,0 +1,231 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2020, Regents of the University of California
+ *
+ * NAC library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * NAC library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of NAC library authors and contributors.
+ */
+
+#include "encryptor.hpp"
+
+#include "tests/boost-test.hpp"
+#include "tests/dummy-forwarder.hpp"
+#include "tests/io-key-chain-fixture.hpp"
+#include "tests/unit/static-data.hpp"
+
+#include <iostream>
+#include <ndn-cxx/util/string-helper.hpp>
+
+namespace ndn {
+namespace nac {
+namespace tests {
+
+class EncryptorStaticDataEnvironment : public IoKeyChainFixture
+{
+public:
+ EncryptorStaticDataEnvironment(bool shouldPublishData)
+ : fw(m_io, m_keyChain)
+ , imsFace(static_cast<util::DummyClientFace&>(fw.addFace()))
+ {
+ if (shouldPublishData) {
+ publishData();
+ }
+
+ auto serveFromIms = [this] (const Name&, const Interest& interest) {
+ auto data = m_ims.find(interest);
+ if (data != nullptr) {
+ imsFace.put(*data);
+ }
+ };
+ imsFace.setInterestFilter("/", serveFromIms, [] (auto...) {});
+ advanceClocks(1_ms, 10);
+
+ imsFace.sentData.clear();
+ imsFace.sentInterests.clear();
+ }
+
+ void
+ publishData()
+ {
+ StaticData data;
+ for (const auto& block : data.managerPackets) {
+ m_ims.insert(*make_shared<Data>(block));
+ }
+ advanceClocks(1_ms, 10);
+ }
+
+public:
+ DummyForwarder fw;
+ util::DummyClientFace& imsFace;
+ InMemoryStoragePersistent m_ims;
+};
+
+template<bool shouldPublishData = true>
+class EncryptorFixture : public EncryptorStaticDataEnvironment
+{
+public:
+ EncryptorFixture()
+ : EncryptorStaticDataEnvironment(shouldPublishData)
+ , face(static_cast<util::DummyClientFace&>(fw.addFace()))
+ , encryptor("/access/policy/identity/NAC/dataset", "/some/ck/prefix", signingWithSha256(),
+ [=] (const ErrorCode& code, const std::string& error) {
+ onFailure(code, error);
+ },
+ validator, m_keyChain, face)
+ {
+ advanceClocks(1_ms, 10);
+ }
+
+public:
+ util::DummyClientFace& face;
+ ValidatorNull validator;
+ Encryptor encryptor;
+ util::Signal<EncryptorFixture, ErrorCode, std::string> onFailure;
+};
+
+BOOST_FIXTURE_TEST_SUITE(TestEncryptor, EncryptorFixture<>)
+
+BOOST_AUTO_TEST_CASE(EncryptAndPublishedCk)
+{
+ encryptor.m_kek.reset();
+ BOOST_CHECK_EQUAL(encryptor.m_isKekRetrievalInProgress, false);
+ encryptor.regenerateCk();
+ BOOST_CHECK_EQUAL(encryptor.m_isKekRetrievalInProgress, true);
+
+ std::string plaintext = "Data to encrypt";
+ auto block = encryptor.encrypt(reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size());
+
+ EncryptedContent content(block);
+ auto ckPrefix = content.getKeyLocator();
+ BOOST_CHECK_EQUAL(ckPrefix.getPrefix(-1), "/some/ck/prefix/CK");
+
+ BOOST_CHECK(content.hasIv());
+ BOOST_CHECK_NE(std::string(reinterpret_cast<const char*>(content.getPayload().value()),
+ content.getPayload().value_size()),
+ plaintext);
+
+ advanceClocks(1_ms, 10);
+
+ // check that KEK interests has been sent
+ BOOST_CHECK_EQUAL(face.sentInterests.at(0).getName().getPrefix(6),
+ Name("/access/policy/identity/NAC/dataset/KEK"));
+
+ auto kek = imsFace.sentData.at(0);
+ BOOST_CHECK_EQUAL(kek.getName().getPrefix(6), Name("/access/policy/identity/NAC/dataset/KEK"));
+ BOOST_CHECK_EQUAL(kek.getName().size(), 7);
+
+ face.sentData.clear();
+ face.sentInterests.clear();
+
+ face.receive(Interest(ckPrefix)
+ .setCanBePrefix(true).setMustBeFresh(true));
+ advanceClocks(1_ms, 10);
+
+ auto ckName = face.sentData.at(0).getName();
+ BOOST_CHECK_EQUAL(ckName.getPrefix(4), "/some/ck/prefix/CK");
+ BOOST_CHECK_EQUAL(ckName.get(5), name::Component("ENCRYPTED-BY"));
+
+ auto extractedKek = ckName.getSubName(6);
+ BOOST_CHECK_EQUAL(extractedKek, kek.getName());
+
+ BOOST_CHECK_EQUAL(encryptor.m_isKekRetrievalInProgress, false);
+}
+
+BOOST_FIXTURE_TEST_CASE(KekRetrievalFailure, EncryptorFixture<false>)
+{
+ size_t nErrors = 0;
+ onFailure.connect([&] (auto&&...) { ++nErrors; });
+
+ std::string plaintext = "Data to encrypt";
+ auto block = encryptor.encrypt(reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size());
+ advanceClocks(1_ms, 10);
+
+ // check that KEK interests has been sent
+ BOOST_CHECK_EQUAL(face.sentInterests.at(0).getName().getPrefix(6), Name("/access/policy/identity/NAC/dataset/KEK"));
+
+ // and failed
+ BOOST_CHECK_EQUAL(imsFace.sentData.size(), 0);
+
+ advanceClocks(1_s, 13); // 4_s default interest lifetime x 3
+ BOOST_CHECK_EQUAL(nErrors, 1);
+ BOOST_CHECK_EQUAL(imsFace.sentData.size(), 0);
+
+ advanceClocks(1_s, 730); // 60 seconds between attempts + ~12 seconds for each attempt
+ BOOST_CHECK_EQUAL(nErrors, 11);
+ BOOST_CHECK_EQUAL(imsFace.sentData.size(), 0);
+
+ // check recovery
+
+ publishData();
+
+ advanceClocks(1_s, 73);
+
+ auto kek = imsFace.sentData.at(0);
+ BOOST_CHECK_EQUAL(kek.getName().getPrefix(6), Name("/access/policy/identity/NAC/dataset/KEK"));
+ BOOST_CHECK_EQUAL(kek.getName().size(), 7);
+}
+
+BOOST_AUTO_TEST_CASE(EnumerateDataFromIms)
+{
+ encryptor.regenerateCk();
+ advanceClocks(1_ms, 10);
+
+ encryptor.regenerateCk();
+ advanceClocks(1_ms, 10);
+
+ BOOST_CHECK_EQUAL(encryptor.size(), 3);
+ size_t nCk = 0;
+ for (const auto& data : encryptor) {
+ BOOST_TEST_MESSAGE(data.getName());
+ if (data.getName().getPrefix(4) == Name("/some/ck/prefix/CK")) {
+ ++nCk;
+ }
+ }
+ BOOST_CHECK_EQUAL(nCk, 3);
+}
+
+BOOST_AUTO_TEST_CASE(DumpPackets) // use this to update content of other test cases
+{
+ if (std::getenv("NAC_DUMP_PACKETS") == nullptr) {
+ return;
+ }
+
+ const auto plaintext = "Data to encrypt"s;
+
+ std::cerr << "const std::vector<Block> encryptedBlobs = {\n";
+ for (size_t i = 0; i < 3; ++i) {
+ std::cerr << " \"";
+ auto block = encryptor.encrypt(reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size());
+ printHex(std::cerr, block.wireEncode().wire(), block.wireEncode().size(), true);
+ std::cerr << "\"_block,\n";
+
+ encryptor.regenerateCk();
+ advanceClocks(1_ms, 10);
+ }
+ std::cerr << "};\n\n";
+
+ std::cerr << "const std::vector<Block> encryptorPackets = {\n";
+ for (const auto& data : encryptor) {
+ std::cerr << " \"";
+ printHex(std::cerr, data.wireEncode().wire(), data.wireEncode().size(), true);
+ std::cerr << "\"_block,\n";
+ }
+ std::cerr << "};\n\n";
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace nac
+} // namespace ndn