blob: 9fad4ec197444ad360abd507f090b4d377902d07 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Junxiao Shi2bea5c42017-08-14 20:10:32 +00002/*
Davide Pesaventoaebf5d72024-12-26 16:04:12 -05003 * Copyright (c) 2013-2025 Regents of the University of California.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Junxiao Shi7b6b79d2014-03-26 20:59:35 -070020 */
21
Davide Pesavento7e780642018-11-24 15:51:34 -050022#include "ndn-cxx/mgmt/nfd/controller.hpp"
Davide Pesaventoaebf5d72024-12-26 16:04:12 -050023#include "ndn-cxx/mgmt/nfd/control-command.hpp"
Davide Pesavento7e780642018-11-24 15:51:34 -050024#include "ndn-cxx/mgmt/nfd/control-response.hpp"
Junxiao Shi7b6b79d2014-03-26 20:59:35 -070025
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -050026#include "tests/test-common.hpp"
Davide Pesavento7e780642018-11-24 15:51:34 -050027#include "tests/unit/mgmt/nfd/controller-fixture.hpp"
Junxiao Shi7b6b79d2014-03-26 20:59:35 -070028
Davide Pesavento47ce2ee2023-05-09 01:33:33 -040029namespace ndn::tests {
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070030
Davide Pesavento47ce2ee2023-05-09 01:33:33 -040031using namespace ndn::nfd;
Junxiao Shi7b6b79d2014-03-26 20:59:35 -070032
Junxiao Shi7357ef22016-09-07 02:39:37 +000033BOOST_AUTO_TEST_SUITE(Mgmt)
34BOOST_AUTO_TEST_SUITE(Nfd)
Junxiao Shi7b6b79d2014-03-26 20:59:35 -070035
Junxiao Shi034c1882016-06-24 18:06:51 +000036class CommandFixture : public ControllerFixture
Junxiao Shi7b6b79d2014-03-26 20:59:35 -070037{
38protected:
Junxiao Shi8c2ab2e2017-05-05 20:26:34 +000039 void
40 respond(const ControlResponse& responsePayload)
41 {
42 auto responseData = makeData(face.sentInterests.at(0).getName());
43 responseData->setContent(responsePayload.wireEncode());
44 face.receive(*responseData);
Davide Pesavento0f830802018-01-16 23:58:58 -050045 this->advanceClocks(1_ms);
Junxiao Shi8c2ab2e2017-05-05 20:26:34 +000046 }
47
Junxiao Shi7b6b79d2014-03-26 20:59:35 -070048protected:
Davide Pesavento09103432023-03-24 20:30:41 -040049 CommandSuccessCallback succeedCallback = [this] (const auto& params) {
Davide Pesavento2e481fc2021-07-02 18:20:03 -040050 succeeds.push_back(params);
51 };
Junxiao Shi034c1882016-06-24 18:06:51 +000052 std::vector<ControlParameters> succeeds;
Junxiao Shi7b6b79d2014-03-26 20:59:35 -070053};
54
Junxiao Shi600f7112016-07-16 11:57:18 +000055// This test suite focuses on ControlCommand functionality of Controller.
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -050056// Individual commands are tested in control-command.t.cpp
57// StatusDataset functionality is tested in status-dataset.t.cpp
Junxiao Shi7357ef22016-09-07 02:39:37 +000058BOOST_FIXTURE_TEST_SUITE(TestController, CommandFixture)
Junxiao Shib1990df2015-11-05 00:14:44 +000059
Junxiao Shi8c2ab2e2017-05-05 20:26:34 +000060static ControlParameters
61makeFaceCreateResponse()
62{
63 ControlParameters resp;
64 resp.setFaceId(22)
65 .setUri("tcp4://192.0.2.1:6363")
66 .setLocalUri("tcp4://192.0.2.2:10847")
67 .setFacePersistency(ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT)
Eric Newberryd567aab2018-01-27 16:38:24 -070068 .setFlags(0x7);
Junxiao Shi8c2ab2e2017-05-05 20:26:34 +000069 return resp;
70}
71
Junxiao Shi600f7112016-07-16 11:57:18 +000072BOOST_AUTO_TEST_CASE(Success)
Junxiao Shi7b6b79d2014-03-26 20:59:35 -070073{
74 ControlParameters parameters;
Junxiao Shi5de006b2014-10-26 20:20:52 -070075 parameters.setUri("tcp4://192.0.2.1:6363");
Junxiao Shi7b6b79d2014-03-26 20:59:35 -070076
Junxiao Shi8c2ab2e2017-05-05 20:26:34 +000077 controller.start<FaceCreateCommand>(parameters, succeedCallback, commandFailCallback);
Davide Pesavento0f830802018-01-16 23:58:58 -050078 this->advanceClocks(1_ms);
Junxiao Shi7b6b79d2014-03-26 20:59:35 -070079
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -080080 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
81 const Interest& requestInterest = face.sentInterests[0];
Junxiao Shi7b6b79d2014-03-26 20:59:35 -070082
Junxiao Shi5de006b2014-10-26 20:20:52 -070083 BOOST_CHECK(Name("/localhost/nfd/faces/create").isPrefixOf(requestInterest.getName()));
Davide Pesavento8fbffe42022-06-15 18:36:03 -040084 BOOST_CHECK(requestInterest.isSigned());
85 BOOST_CHECK(requestInterest.isParametersDigestValid());
Junxiao Shi415b17c2014-11-12 00:43:25 -070086 BOOST_CHECK_EQUAL(requestInterest.getInterestLifetime(), CommandOptions::DEFAULT_TIMEOUT);
Junxiao Shi7b6b79d2014-03-26 20:59:35 -070087
Davide Pesavento8fbffe42022-06-15 18:36:03 -040088 // 6 components: /localhost/nfd/faces/create/<parameters>/params-sha256=...
89 BOOST_REQUIRE_EQUAL(requestInterest.getName().size(), 6);
90 ControlParameters requestParams(requestInterest.getName()[4].blockFromValue());
Davide Pesaventoaebf5d72024-12-26 16:04:12 -050091 BOOST_CHECK_NO_THROW(FaceCreateCommand::validateRequest(requestParams));
Davide Pesavento8fbffe42022-06-15 18:36:03 -040092 BOOST_CHECK_EQUAL(requestParams.getUri(), parameters.getUri());
93
Junxiao Shi8c2ab2e2017-05-05 20:26:34 +000094 ControlParameters responseBody = makeFaceCreateResponse();
Junxiao Shi7b6b79d2014-03-26 20:59:35 -070095 ControlResponse responsePayload(201, "created");
96 responsePayload.setBody(responseBody.wireEncode());
Junxiao Shi8c2ab2e2017-05-05 20:26:34 +000097 this->respond(responsePayload);
Junxiao Shi7b6b79d2014-03-26 20:59:35 -070098
Junxiao Shi034c1882016-06-24 18:06:51 +000099 BOOST_CHECK_EQUAL(failCodes.size(), 0);
100 BOOST_REQUIRE_EQUAL(succeeds.size(), 1);
101 BOOST_CHECK_EQUAL(succeeds.back().getUri(), responseBody.getUri());
102 BOOST_CHECK_EQUAL(succeeds.back().getFaceId(), responseBody.getFaceId());
Junxiao Shi7b6b79d2014-03-26 20:59:35 -0700103}
104
Junxiao Shi600f7112016-07-16 11:57:18 +0000105BOOST_AUTO_TEST_CASE(SuccessNoCallback)
106{
107 ControlParameters parameters;
108 parameters.setUri("tcp4://192.0.2.1:6363");
109
Junxiao Shie7c7f152016-08-20 22:36:22 +0000110 controller.start<FaceCreateCommand>(parameters, nullptr, commandFailCallback);
Davide Pesavento0f830802018-01-16 23:58:58 -0500111 this->advanceClocks(1_ms);
Junxiao Shi600f7112016-07-16 11:57:18 +0000112
Junxiao Shi8c2ab2e2017-05-05 20:26:34 +0000113 ControlParameters responseBody = makeFaceCreateResponse();
Junxiao Shi600f7112016-07-16 11:57:18 +0000114 ControlResponse responsePayload(201, "created");
115 responsePayload.setBody(responseBody.wireEncode());
Junxiao Shi8c2ab2e2017-05-05 20:26:34 +0000116 this->respond(responsePayload);
Junxiao Shi600f7112016-07-16 11:57:18 +0000117
118 BOOST_CHECK_EQUAL(failCodes.size(), 0);
119}
120
121BOOST_AUTO_TEST_CASE(OptionsPrefix)
122{
123 ControlParameters parameters;
124 parameters.setName("/ndn/com/example");
125 parameters.setFaceId(400);
126
127 CommandOptions options;
128 options.setPrefix("/localhop/net/example/router1/nfd");
129
Junxiao Shi8c2ab2e2017-05-05 20:26:34 +0000130 controller.start<RibRegisterCommand>(parameters, succeedCallback, commandFailCallback, options);
Davide Pesavento0f830802018-01-16 23:58:58 -0500131 this->advanceClocks(1_ms);
Junxiao Shi600f7112016-07-16 11:57:18 +0000132
133 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
Davide Pesaventoaebf5d72024-12-26 16:04:12 -0500134 const Interest& request = face.sentInterests[0];
Junxiao Shi600f7112016-07-16 11:57:18 +0000135
Davide Pesaventoaebf5d72024-12-26 16:04:12 -0500136 BOOST_CHECK(Name("/localhop/net/example/router1/nfd/rib/register").isPrefixOf(request.getName()));
137 BOOST_CHECK(request.isSigned());
138 BOOST_CHECK(request.isParametersDigestValid());
Junxiao Shi600f7112016-07-16 11:57:18 +0000139}
140
141BOOST_AUTO_TEST_CASE(InvalidRequest)
Junxiao Shi7b6b79d2014-03-26 20:59:35 -0700142{
jaczhi82d8ed02025-01-07 15:51:02 -0800143 ControlParameters p1;
144 p1.setName("/should-not-have-this-field");
Junxiao Shi7b6b79d2014-03-26 20:59:35 -0700145 // Uri is missing
jaczhi82d8ed02025-01-07 15:51:02 -0800146 BOOST_CHECK_THROW(controller.start<FaceCreateCommand>(p1, succeedCallback, commandFailCallback),
147 ArgumentError);
Junxiao Shi7b6b79d2014-03-26 20:59:35 -0700148
jaczhi82d8ed02025-01-07 15:51:02 -0800149 RibAnnounceParameters p2;
150 // PrefixAnnouncement not signed
151 BOOST_CHECK_THROW(controller.start<RibAnnounceCommand>(p2, succeedCallback, commandFailCallback),
Davide Pesaventoaebf5d72024-12-26 16:04:12 -0500152 ArgumentError);
Junxiao Shi7b6b79d2014-03-26 20:59:35 -0700153}
154
Junxiao Shi54f727d2016-08-08 20:29:11 +0000155BOOST_AUTO_TEST_CASE(ValidationFailure)
156{
157 this->setValidationResult(false);
158
159 ControlParameters parameters;
160 parameters.setUri("tcp4://192.0.2.1:6363");
161
Junxiao Shi8c2ab2e2017-05-05 20:26:34 +0000162 controller.start<FaceCreateCommand>(parameters, succeedCallback, commandFailCallback);
Davide Pesavento0f830802018-01-16 23:58:58 -0500163 this->advanceClocks(1_ms);
Junxiao Shi54f727d2016-08-08 20:29:11 +0000164
Junxiao Shi8c2ab2e2017-05-05 20:26:34 +0000165 ControlParameters responseBody = makeFaceCreateResponse();
Junxiao Shi54f727d2016-08-08 20:29:11 +0000166 ControlResponse responsePayload(201, "created");
167 responsePayload.setBody(responseBody.wireEncode());
Junxiao Shi8c2ab2e2017-05-05 20:26:34 +0000168 this->respond(responsePayload);
Junxiao Shi54f727d2016-08-08 20:29:11 +0000169
170 BOOST_CHECK_EQUAL(succeeds.size(), 0);
171 BOOST_REQUIRE_EQUAL(failCodes.size(), 1);
172 BOOST_CHECK_EQUAL(failCodes.back(), Controller::ERROR_VALIDATION);
173}
174
Junxiao Shi600f7112016-07-16 11:57:18 +0000175BOOST_AUTO_TEST_CASE(ErrorCode)
Junxiao Shi7b6b79d2014-03-26 20:59:35 -0700176{
177 ControlParameters parameters;
Junxiao Shi5de006b2014-10-26 20:20:52 -0700178 parameters.setUri("tcp4://192.0.2.1:6363");
Junxiao Shi7b6b79d2014-03-26 20:59:35 -0700179
Junxiao Shi8c2ab2e2017-05-05 20:26:34 +0000180 controller.start<FaceCreateCommand>(parameters, succeedCallback, commandFailCallback);
Davide Pesavento0f830802018-01-16 23:58:58 -0500181 this->advanceClocks(1_ms);
Junxiao Shi7b6b79d2014-03-26 20:59:35 -0700182
Junxiao Shi7b6b79d2014-03-26 20:59:35 -0700183 ControlResponse responsePayload(401, "Not Authenticated");
Junxiao Shi8c2ab2e2017-05-05 20:26:34 +0000184 this->respond(responsePayload);
Junxiao Shi7b6b79d2014-03-26 20:59:35 -0700185
Junxiao Shi034c1882016-06-24 18:06:51 +0000186 BOOST_CHECK_EQUAL(succeeds.size(), 0);
187 BOOST_REQUIRE_EQUAL(failCodes.size(), 1);
188 BOOST_CHECK_EQUAL(failCodes.back(), 401);
Junxiao Shi7b6b79d2014-03-26 20:59:35 -0700189}
190
Junxiao Shi600f7112016-07-16 11:57:18 +0000191BOOST_AUTO_TEST_CASE(InvalidResponse)
Junxiao Shi7b6b79d2014-03-26 20:59:35 -0700192{
193 ControlParameters parameters;
Junxiao Shi5de006b2014-10-26 20:20:52 -0700194 parameters.setUri("tcp4://192.0.2.1:6363");
Junxiao Shi7b6b79d2014-03-26 20:59:35 -0700195
Junxiao Shi8c2ab2e2017-05-05 20:26:34 +0000196 controller.start<FaceCreateCommand>(parameters, succeedCallback, commandFailCallback);
Davide Pesavento0f830802018-01-16 23:58:58 -0500197 this->advanceClocks(1_ms);
Junxiao Shi7b6b79d2014-03-26 20:59:35 -0700198
Junxiao Shi8c2ab2e2017-05-05 20:26:34 +0000199 ControlParameters responseBody = makeFaceCreateResponse();
200 responseBody.unsetFaceId() // FaceId is missing
Junxiao Shi7b6b79d2014-03-26 20:59:35 -0700201 .setName("ndn:/should-not-have-this-field");
Junxiao Shi7b6b79d2014-03-26 20:59:35 -0700202 ControlResponse responsePayload(201, "created");
203 responsePayload.setBody(responseBody.wireEncode());
Junxiao Shi8c2ab2e2017-05-05 20:26:34 +0000204 this->respond(responsePayload);
Junxiao Shi7b6b79d2014-03-26 20:59:35 -0700205
Junxiao Shi034c1882016-06-24 18:06:51 +0000206 BOOST_CHECK_EQUAL(succeeds.size(), 0);
207 BOOST_REQUIRE_EQUAL(failCodes.size(), 1);
Junxiao Shi7b6b79d2014-03-26 20:59:35 -0700208}
209
Junxiao Shi600f7112016-07-16 11:57:18 +0000210BOOST_AUTO_TEST_CASE(Nack)
Junxiao Shib1990df2015-11-05 00:14:44 +0000211{
212 ControlParameters parameters;
213 parameters.setUri("tcp4://192.0.2.1:6363");
214
Junxiao Shi8c2ab2e2017-05-05 20:26:34 +0000215 controller.start<FaceCreateCommand>(parameters, succeedCallback, commandFailCallback);
Davide Pesavento0f830802018-01-16 23:58:58 -0500216 this->advanceClocks(1_ms);
Junxiao Shib1990df2015-11-05 00:14:44 +0000217
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800218 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
219 const Interest& requestInterest = face.sentInterests[0];
Junxiao Shib1990df2015-11-05 00:14:44 +0000220
Junxiao Shi034c1882016-06-24 18:06:51 +0000221 auto responseNack = makeNack(requestInterest, lp::NackReason::NO_ROUTE);
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800222 face.receive(responseNack);
Davide Pesavento0f830802018-01-16 23:58:58 -0500223 this->advanceClocks(1_ms);
Junxiao Shib1990df2015-11-05 00:14:44 +0000224
Junxiao Shi034c1882016-06-24 18:06:51 +0000225 BOOST_REQUIRE_EQUAL(failCodes.size(), 1);
226 BOOST_CHECK_EQUAL(failCodes.back(), Controller::ERROR_NACK);
Junxiao Shib1990df2015-11-05 00:14:44 +0000227}
228
Junxiao Shi600f7112016-07-16 11:57:18 +0000229BOOST_AUTO_TEST_CASE(Timeout)
Junxiao Shi5de006b2014-10-26 20:20:52 -0700230{
231 ControlParameters parameters;
232 parameters.setUri("tcp4://192.0.2.1:6363");
233
234 CommandOptions options;
Davide Pesavento0f830802018-01-16 23:58:58 -0500235 options.setTimeout(50_ms);
Junxiao Shi5de006b2014-10-26 20:20:52 -0700236
Junxiao Shi8c2ab2e2017-05-05 20:26:34 +0000237 controller.start<FaceCreateCommand>(parameters, succeedCallback, commandFailCallback, options);
Davide Pesavento0f830802018-01-16 23:58:58 -0500238 this->advanceClocks(1_ms); // express Interest
239 this->advanceClocks(51_ms); // timeout
Junxiao Shi5de006b2014-10-26 20:20:52 -0700240
Junxiao Shi034c1882016-06-24 18:06:51 +0000241 BOOST_REQUIRE_EQUAL(failCodes.size(), 1);
242 BOOST_CHECK_EQUAL(failCodes.back(), Controller::ERROR_TIMEOUT);
Junxiao Shi5de006b2014-10-26 20:20:52 -0700243}
244
Junxiao Shi600f7112016-07-16 11:57:18 +0000245BOOST_AUTO_TEST_CASE(FailureNoCallback)
246{
247 ControlParameters parameters;
248 parameters.setUri("tcp4://192.0.2.1:6363");
Junxiao Shi7b6b79d2014-03-26 20:59:35 -0700249
Junxiao Shi600f7112016-07-16 11:57:18 +0000250 CommandOptions options;
Davide Pesavento0f830802018-01-16 23:58:58 -0500251 options.setTimeout(50_ms);
Junxiao Shi600f7112016-07-16 11:57:18 +0000252
253 controller.start<FaceCreateCommand>(parameters, succeedCallback, nullptr, options);
Davide Pesavento0f830802018-01-16 23:58:58 -0500254 this->advanceClocks(1_ms); // express Interest
255 this->advanceClocks(51_ms); // timeout
Junxiao Shi600f7112016-07-16 11:57:18 +0000256
257 BOOST_CHECK_EQUAL(succeeds.size(), 0);
258}
259
Junxiao Shi7357ef22016-09-07 02:39:37 +0000260BOOST_AUTO_TEST_SUITE_END() // TestController
261BOOST_AUTO_TEST_SUITE_END() // Nfd
262BOOST_AUTO_TEST_SUITE_END() // Mgmt
Junxiao Shi034c1882016-06-24 18:06:51 +0000263
Davide Pesavento47ce2ee2023-05-09 01:33:33 -0400264} // namespace ndn::tests