blob: ae5d7003cdd3c6dbb61073c8bbf41bdbbef22619 [file] [log] [blame]
Tomáš Peckaf10b9302021-02-23 19:02:02 +01001/*
2 * Copyright (C) 2021 CESNET, https://photonics.cesnet.cz/
3 *
4 * Written by Tomáš Pecka <tomas.pecka@cesnet.cz>
5 *
6*/
7
8#include "trompeloeil_doctest.h"
Tomáš Pecka39bbb512021-05-23 22:07:22 +02009#include <filesystem>
Václav Kubernát7efd6d52021-11-09 01:31:11 +010010#include <sysrepo-cpp/utils/exception.hpp>
Tomáš Peckaf10b9302021-02-23 19:02:02 +010011#include "pretty_printers.h"
12#include "system/IETFInterfaces.h"
Tomáš Pecka39bbb512021-05-23 22:07:22 +020013#include "system/IETFInterfacesConfig.h"
Tomáš Peckaf10b9302021-02-23 19:02:02 +010014#include "test_log_setup.h"
15#include "test_sysrepo_helpers.h"
Tomáš Pecka39bbb512021-05-23 22:07:22 +020016#include "tests/configure.cmake.h"
Tomáš Peckaf10b9302021-02-23 19:02:02 +010017#include "tests/mock/system.h"
Tomáš Pecka39bbb512021-05-23 22:07:22 +020018#include "utils/io.h"
Tomáš Peckaf10b9302021-02-23 19:02:02 +010019
Tomáš Pecka71a98b02021-05-17 15:59:40 +020020using namespace std::string_literals;
21
Tomáš Peckaf10b9302021-02-23 19:02:02 +010022TEST_CASE("ietf-interfaces localhost")
23{
24 TEST_SYSREPO_INIT_LOGS;
25 TEST_SYSREPO_INIT;
26 TEST_SYSREPO_INIT_CLIENT;
27
28 auto network = std::make_shared<velia::system::IETFInterfaces>(srSess);
29
30 // We didn't came up with some way of mocking netlink. At least check that there is the loopback
31 // interface with expected values. It is *probably* safe to assume that there is at least the lo device.
Václav Kubernát7efd6d52021-11-09 01:31:11 +010032 auto lo = dataFromSysrepo(client, "/ietf-interfaces:interfaces/interface[name='lo']", sysrepo::Datastore::Operational);
Tomáš Pecka70e54562021-03-10 12:39:03 +010033
34 // ensure statistics keys exist and remove them ; we can't really predict the content
Václav Kubernát7efd6d52021-11-09 01:31:11 +010035 for (const auto& key : {"/statistics/in-discards", "/statistics/in-errors", "/statistics/in-octets", "/statistics/out-discards", "/statistics/out-errors", "/statistics/out-octets"}) {
Tomáš Pecka70e54562021-03-10 12:39:03 +010036 auto it = lo.find(key);
37 REQUIRE(it != lo.end());
38 lo.erase(it);
39 }
40
Tomáš Peckabd43a942021-08-04 10:12:49 +020041 REQUIRE(lo == std::map<std::string, std::string>{
Tomáš Peckaf10b9302021-02-23 19:02:02 +010042 {"/name", "lo"},
43 {"/type", "iana-if-type:softwareLoopback"},
44 {"/phys-address", "00:00:00:00:00:00"},
45 {"/oper-status", "unknown"},
Tomáš Pecka09729382021-03-08 19:36:50 +010046 {"/ietf-ip:ipv4", ""},
47 {"/ietf-ip:ipv4/address[ip='127.0.0.1']", ""},
48 {"/ietf-ip:ipv4/address[ip='127.0.0.1']/ip", "127.0.0.1"},
49 {"/ietf-ip:ipv4/address[ip='127.0.0.1']/prefix-length", "8"},
50 {"/ietf-ip:ipv6", ""},
Tomáš Peckabd43a942021-08-04 10:12:49 +020051 {"/ietf-ip:ipv6/autoconf", ""},
Tomáš Pecka09729382021-03-08 19:36:50 +010052 {"/ietf-ip:ipv6/address[ip='::1']", ""},
53 {"/ietf-ip:ipv6/address[ip='::1']/ip", "::1"},
54 {"/ietf-ip:ipv6/address[ip='::1']/prefix-length", "128"},
Václav Kubernát7efd6d52021-11-09 01:31:11 +010055 {"/statistics", ""},
Tomáš Peckaf10b9302021-02-23 19:02:02 +010056 });
Tomáš Pecka3663aae2021-03-10 13:46:31 +010057 // NOTE: There are no neighbours on loopback
Tomáš Pecka4c7ff2a2021-08-06 15:05:54 +020058}
59
60struct FakeNetworkReload {
61public:
62 MAKE_CONST_MOCK1(cb, void(const std::vector<std::string>&));
63};
64
65TEST_CASE("Config data in ietf-interfaces")
66{
67 TEST_SYSREPO_INIT_LOGS;
68 TEST_SYSREPO_INIT;
69 TEST_SYSREPO_INIT_CLIENT;
70 trompeloeil::sequence seq1;
71
Tomáš Pecka9cb218c2022-06-13 11:48:20 +020072 sysrepo::Connection{}.sessionStart(sysrepo::Datastore::Running).copyConfig(sysrepo::Datastore::Startup, "ietf-interfaces");
73
Tomáš Pecka4c7ff2a2021-08-06 15:05:54 +020074 auto fake = FakeNetworkReload();
75
76 const auto fakeConfigDir = std::filesystem::path(CMAKE_CURRENT_BINARY_DIR) / "tests/network/"s;
77 std::filesystem::remove_all(fakeConfigDir);
78 std::filesystem::create_directories(fakeConfigDir);
79
Jan Kundrát80113ed2022-04-27 18:10:52 +020080 REQUIRE_CALL(fake, cb(std::vector<std::string>{})).IN_SEQUENCE(seq1);
Tomáš Pecka4c7ff2a2021-08-06 15:05:54 +020081 auto network = std::make_shared<velia::system::IETFInterfacesConfig>(srSess, fakeConfigDir, std::vector<std::string>{"br0", "eth0", "eth1"}, [&fake](const std::vector<std::string>& updatedInterfaces) { fake.cb(updatedInterfaces); });
Tomáš Pecka71a98b02021-05-17 15:59:40 +020082
83 SECTION("Link changes disabled")
84 {
Tomáš Pecka71a98b02021-05-17 15:59:40 +020085 SECTION("Only specified link names can appear in configurable datastore")
86 {
87 for (const auto& [name, type] : {std::pair<const char*, const char*>{"eth0", "iana-if-type:ethernetCsmacd"},
88 {"eth1", "iana-if-type:ethernetCsmacd"},
89 {"br0", "iana-if-type:bridge"},
90 {"osc", "iana-if-type:ethernetCsmacd"},
91 {"oscW", "iana-if-type:ethernetCsmacd"},
92 {"oscE", "iana-if-type:ethernetCsmacd"}}) {
Jan Kundrátb3e99982022-03-18 17:38:20 +010093 client.setItem("/ietf-interfaces:interfaces/interface[name='"s + name + "']/type", type);
94 client.setItem("/ietf-interfaces:interfaces/interface[name='"s + name + "']/enabled", "false");
Tomáš Pecka71a98b02021-05-17 15:59:40 +020095 }
Tomáš Pecka9cb218c2022-06-13 11:48:20 +020096
97 REQUIRE_CALL(fake, cb(std::vector<std::string>{"br0", "eth0", "eth1"})).IN_SEQUENCE(seq1); // only these are monitored by the test
Václav Kubernát7efd6d52021-11-09 01:31:11 +010098 client.applyChanges();
Tomáš Pecka71a98b02021-05-17 15:59:40 +020099 }
100
101 SECTION("Invalid type for a valid link")
102 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100103 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/type", "iana-if-type:softwareLoopback");
104 REQUIRE_THROWS_AS(client.applyChanges(), sysrepo::ErrorWithCode);
Tomáš Pecka71a98b02021-05-17 15:59:40 +0200105 }
106
107 SECTION("Invalid name")
108 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100109 client.setItem("/ietf-interfaces:interfaces/interface[name='blah0']/type", "iana-if-type:ethernetCsmacd");
110 REQUIRE_THROWS_AS(client.applyChanges(), sysrepo::ErrorWithCode);
Tomáš Pecka71a98b02021-05-17 15:59:40 +0200111 }
112 }
Tomáš Peckade0ef2f2021-07-08 13:23:50 +0200113
114 SECTION("There must always be enabled protocol or the interface must be explicitely disabled")
115 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100116 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/type", "iana-if-type:ethernetCsmacd");
Tomáš Peckade0ef2f2021-07-08 13:23:50 +0200117
118 SECTION("Disabled protocols; enabled link")
119 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100120 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/enabled", "true");
121 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:enabled", "false");
122 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:enabled", "false");
123 REQUIRE_THROWS_AS(client.applyChanges(), sysrepo::ErrorWithCode);
Tomáš Peckade0ef2f2021-07-08 13:23:50 +0200124 }
125
126 SECTION("Active protocols; disabled link")
127 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100128 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/enabled", "false");
129 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:enabled", "false");
130 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:enabled", "true");
131 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:address[ip='2001:db8::1']/ietf-ip:prefix-length", "32");
Tomáš Pecka4c7ff2a2021-08-06 15:05:54 +0200132 REQUIRE_CALL(fake, cb(std::vector<std::string>{"eth0"})).IN_SEQUENCE(seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100133 client.applyChanges();
Tomáš Peckade0ef2f2021-07-08 13:23:50 +0200134 }
135
136 SECTION("IPv4 only; enabled link")
137 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100138 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/enabled", "true");
139 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:enabled", "true");
140 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:address[ip='192.0.2.1']/ietf-ip:prefix-length", "24");
141 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:enabled", "false");
Tomáš Pecka4c7ff2a2021-08-06 15:05:54 +0200142 REQUIRE_CALL(fake, cb(std::vector<std::string>{"eth0"})).IN_SEQUENCE(seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100143 client.applyChanges();
Tomáš Peckade0ef2f2021-07-08 13:23:50 +0200144 }
145 }
146
147 SECTION("Every active protocol must have at least one IP address assigned")
148 {
Tomáš Pecka9cb218c2022-06-13 11:48:20 +0200149 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/type", "iana-if-type:ethernetCsmacd");
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100150 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/enabled", "false");
Tomáš Pecka4c7ff2a2021-08-06 15:05:54 +0200151 REQUIRE_CALL(fake, cb(std::vector<std::string>{"eth0"})).IN_SEQUENCE(seq1).TIMES(AT_MOST(1));
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100152 client.applyChanges();
Tomáš Peckade0ef2f2021-07-08 13:23:50 +0200153
154 SECTION("Enabled IPv4 protocol with some IPs assigned is valid")
155 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100156 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/enabled", "true");
157 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:enabled", "true");
158 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:address[ip='192.0.2.1']/ietf-ip:prefix-length", "24");
159 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:address[ip='192.0.2.2']/ietf-ip:prefix-length", "24");
160 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:enabled", "false");
Tomáš Pecka4c7ff2a2021-08-06 15:05:54 +0200161 REQUIRE_CALL(fake, cb(std::vector<std::string>{"eth0"})).IN_SEQUENCE(seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100162 client.applyChanges();
Tomáš Peckade0ef2f2021-07-08 13:23:50 +0200163 }
164
165 SECTION("Enabled IPv6 protocol with some IPs assigned is valid")
166 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100167 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/enabled", "true");
168 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:enabled", "false");
169 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:enabled", "true");
170 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:address[ip='2001:db8::1']/ietf-ip:prefix-length", "32");
Tomáš Pecka4c7ff2a2021-08-06 15:05:54 +0200171 REQUIRE_CALL(fake, cb(std::vector<std::string>{"eth0"})).IN_SEQUENCE(seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100172 client.applyChanges();
Tomáš Peckade0ef2f2021-07-08 13:23:50 +0200173 }
174
Tomáš Peckabd43a942021-08-04 10:12:49 +0200175 SECTION("Enabled IPv4 protocol must have at least one IP or the autoconfiguration must be on")
Tomáš Peckade0ef2f2021-07-08 13:23:50 +0200176 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100177 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/enabled", "true");
178 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:enabled", "true");
179 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/czechlight-network:dhcp-client", "false");
180 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:enabled", "false");
181 REQUIRE_THROWS_AS(client.applyChanges(), sysrepo::ErrorWithCode);
Tomáš Peckade0ef2f2021-07-08 13:23:50 +0200182 }
183
Tomáš Peckabd43a942021-08-04 10:12:49 +0200184 SECTION("Enabled IPv6 protocol must have at least one IP or the autoconfiguration must be on")
Tomáš Peckade0ef2f2021-07-08 13:23:50 +0200185 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100186 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/enabled", "true");
187 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:enabled", "false");
188 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:enabled", "true");
189 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:autoconf/ietf-ip:create-global-addresses", "false");
190 REQUIRE_THROWS_AS(client.applyChanges(), sysrepo::ErrorWithCode);
Tomáš Peckade0ef2f2021-07-08 13:23:50 +0200191 }
192 }
Tomáš Pecka39bbb512021-05-23 22:07:22 +0200193
194 std::string expectedContents;
Tomáš Peckabd43a942021-08-04 10:12:49 +0200195
Tomáš Pecka85f77752021-06-03 10:09:58 +0200196 SECTION("Setting IPs to eth0")
Tomáš Pecka39bbb512021-05-23 22:07:22 +0200197 {
Tomáš Pecka85f77752021-06-03 10:09:58 +0200198 const auto expectedFilePath = fakeConfigDir / "eth0.network";
199
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100200 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/type", "iana-if-type:ethernetCsmacd");
Tomáš Pecka85f77752021-06-03 10:09:58 +0200201
202 SECTION("Single IPv4 address")
203 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100204 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/description", "Hello world");
205 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:address[ip='192.0.2.1']/ietf-ip:prefix-length", "24");
206 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/czechlight-network:dhcp-client", "false");
Tomáš Pecka85f77752021-06-03 10:09:58 +0200207 expectedContents = R"([Match]
Tomáš Pecka39bbb512021-05-23 22:07:22 +0200208Name=eth0
209
210[Network]
211Description=Hello world
Tomáš Pecka85f77752021-06-03 10:09:58 +0200212Address=192.0.2.1/24
213LinkLocalAddressing=no
Tomáš Peckabd43a942021-08-04 10:12:49 +0200214IPv6AcceptRA=false
Tomáš Pecka85f77752021-06-03 10:09:58 +0200215DHCP=no
Tomáš Pecka39bbb512021-05-23 22:07:22 +0200216LLDP=true
217EmitLLDP=nearest-bridge
218)";
Tomáš Pecka85f77752021-06-03 10:09:58 +0200219 }
Tomáš Pecka39bbb512021-05-23 22:07:22 +0200220
Tomáš Pecka85f77752021-06-03 10:09:58 +0200221 SECTION("Two IPv4 addresses")
222 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100223 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:address[ip='192.0.2.1']/ietf-ip:prefix-length", "24");
224 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:address[ip='192.0.2.2']/ietf-ip:prefix-length", "24");
225 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/czechlight-network:dhcp-client", "false");
226 client.deleteItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6");
Tomáš Pecka85f77752021-06-03 10:09:58 +0200227 expectedContents = R"([Match]
Tomáš Pecka39bbb512021-05-23 22:07:22 +0200228Name=eth0
229
230[Network]
Tomáš Pecka85f77752021-06-03 10:09:58 +0200231Address=192.0.2.1/24
232Address=192.0.2.2/24
233LinkLocalAddressing=no
Tomáš Peckabd43a942021-08-04 10:12:49 +0200234IPv6AcceptRA=false
Tomáš Pecka85f77752021-06-03 10:09:58 +0200235DHCP=no
Tomáš Pecka39bbb512021-05-23 22:07:22 +0200236LLDP=true
237EmitLLDP=nearest-bridge
238)";
Tomáš Pecka85f77752021-06-03 10:09:58 +0200239 }
240
241 SECTION("IPv4 and IPv6 addresses")
242 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100243 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:address[ip='192.0.2.1']/ietf-ip:prefix-length", "24");
244 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:address[ip='2001:db8::1']/ietf-ip:prefix-length", "32");
245 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/czechlight-network:dhcp-client", "false");
Tomáš Pecka85f77752021-06-03 10:09:58 +0200246 expectedContents = R"([Match]
247Name=eth0
248
249[Network]
250Address=192.0.2.1/24
251Address=2001:db8::1/32
Tomáš Peckabd43a942021-08-04 10:12:49 +0200252IPv6AcceptRA=true
Tomáš Pecka85f77752021-06-03 10:09:58 +0200253DHCP=no
254LLDP=true
255EmitLLDP=nearest-bridge
256)";
257 }
258
259 SECTION("IPv4 and IPv6 addresses but IPv6 disabled")
260 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100261 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:address[ip='192.0.2.1']/ietf-ip:prefix-length", "24");
262 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:address[ip='2001:db8::1']/ietf-ip:prefix-length", "32");
263 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/czechlight-network:dhcp-client", "false");
264 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/enabled", "false");
Tomáš Pecka85f77752021-06-03 10:09:58 +0200265 expectedContents = R"([Match]
266Name=eth0
267
268[Network]
269Address=192.0.2.1/24
270LinkLocalAddressing=no
Tomáš Peckabd43a942021-08-04 10:12:49 +0200271IPv6AcceptRA=false
Tomáš Pecka85f77752021-06-03 10:09:58 +0200272DHCP=no
273LLDP=true
274EmitLLDP=nearest-bridge
275)";
276 }
277
278 REQUIRE_CALL(fake, cb(std::vector<std::string>{"eth0"})).IN_SEQUENCE(seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100279 client.applyChanges();
Tomáš Pecka85f77752021-06-03 10:09:58 +0200280 REQUIRE(std::filesystem::exists(expectedFilePath));
281 REQUIRE(velia::utils::readFileToString(expectedFilePath) == expectedContents);
282
283 // reset the contents
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100284 client.deleteItem("/ietf-interfaces:interfaces/interface[name='eth0']");
Tomáš Pecka85f77752021-06-03 10:09:58 +0200285 REQUIRE_CALL(fake, cb(std::vector<std::string>{"eth0"})).IN_SEQUENCE(seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100286 client.applyChanges();
Tomáš Pecka85f77752021-06-03 10:09:58 +0200287 REQUIRE(!std::filesystem::exists(expectedFilePath));
Tomáš Pecka39bbb512021-05-23 22:07:22 +0200288 }
289
Tomáš Peckac2929a62021-06-05 17:21:03 +0200290 SECTION("Two links")
Tomáš Pecka85f77752021-06-03 10:09:58 +0200291 {
292 const auto expectedFilePathEth0 = fakeConfigDir / "eth0.network";
293 const auto expectedFilePathEth1 = fakeConfigDir / "eth1.network";
Tomáš Peckac2929a62021-06-05 17:21:03 +0200294
295 std::string expectedContentsEth0 = R"([Match]
Tomáš Pecka85f77752021-06-03 10:09:58 +0200296Name=eth0
Tomáš Pecka39bbb512021-05-23 22:07:22 +0200297
Tomáš Pecka85f77752021-06-03 10:09:58 +0200298[Network]
299Address=192.0.2.1/24
300LinkLocalAddressing=no
Tomáš Peckabd43a942021-08-04 10:12:49 +0200301IPv6AcceptRA=false
Tomáš Pecka85f77752021-06-03 10:09:58 +0200302DHCP=no
303LLDP=true
304EmitLLDP=nearest-bridge
305)";
Tomáš Peckac2929a62021-06-05 17:21:03 +0200306 std::string expectedContentsEth1 = R"([Match]
Tomáš Pecka85f77752021-06-03 10:09:58 +0200307Name=eth1
Tomáš Pecka39bbb512021-05-23 22:07:22 +0200308
Tomáš Pecka85f77752021-06-03 10:09:58 +0200309[Network]
310Address=2001:db8::1/32
Tomáš Peckabd43a942021-08-04 10:12:49 +0200311IPv6AcceptRA=true
Tomáš Pecka85f77752021-06-03 10:09:58 +0200312DHCP=no
313LLDP=true
314EmitLLDP=nearest-bridge
315)";
316
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100317 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/type", "iana-if-type:ethernetCsmacd");
318 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:address[ip='192.0.2.1']/ietf-ip:prefix-length", "24");
319 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/czechlight-network:dhcp-client", "false");
320 client.setItem("/ietf-interfaces:interfaces/interface[name='eth1']/type", "iana-if-type:ethernetCsmacd");
321 client.setItem("/ietf-interfaces:interfaces/interface[name='eth1']/ietf-ip:ipv6/ietf-ip:address[ip='2001:db8::1']/ietf-ip:prefix-length", "32");
Tomáš Pecka85f77752021-06-03 10:09:58 +0200322
323 REQUIRE_CALL(fake, cb(std::vector<std::string>{"eth0", "eth1"})).IN_SEQUENCE(seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100324 client.applyChanges();
Tomáš Pecka85f77752021-06-03 10:09:58 +0200325 REQUIRE(std::filesystem::exists(expectedFilePathEth0));
326 REQUIRE(std::filesystem::exists(expectedFilePathEth1));
327 REQUIRE(velia::utils::readFileToString(expectedFilePathEth0) == expectedContentsEth0);
328 REQUIRE(velia::utils::readFileToString(expectedFilePathEth1) == expectedContentsEth1);
329
330 // reset the contents
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100331 client.deleteItem("/ietf-interfaces:interfaces/interface[name='eth0']");
332 client.deleteItem("/ietf-interfaces:interfaces/interface[name='eth1']");
Tomáš Pecka85f77752021-06-03 10:09:58 +0200333 REQUIRE_CALL(fake, cb(std::vector<std::string>{"eth0", "eth1"})).IN_SEQUENCE(seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100334 client.applyChanges();
Tomáš Pecka85f77752021-06-03 10:09:58 +0200335 REQUIRE(!std::filesystem::exists(expectedFilePathEth0));
336 REQUIRE(!std::filesystem::exists(expectedFilePathEth1));
337 }
Tomáš Peckac2929a62021-06-05 17:21:03 +0200338
339 SECTION("Setup a bridge br0 over eth0 and eth1")
340 {
341 const auto expectedFilePathBr0 = fakeConfigDir / "br0.network";
342 const auto expectedFilePathEth0 = fakeConfigDir / "eth0.network";
343 const auto expectedFilePathEth1 = fakeConfigDir / "eth1.network";
344
345 std::string expectedContentsBr0 = R"([Match]
346Name=br0
347
348[Network]
349LinkLocalAddressing=no
Tomáš Peckabd43a942021-08-04 10:12:49 +0200350IPv6AcceptRA=false
Tomáš Peckac2929a62021-06-05 17:21:03 +0200351DHCP=no
352LLDP=true
353EmitLLDP=nearest-bridge
354)";
355
356 std::string expectedContentsEth0 = R"([Match]
357Name=eth0
358
359[Network]
360Bridge=br0
Tomáš Peckabd43a942021-08-04 10:12:49 +0200361IPv6AcceptRA=false
Tomáš Peckac2929a62021-06-05 17:21:03 +0200362DHCP=no
363LLDP=true
364EmitLLDP=nearest-bridge
365)";
366
367 std::string expectedContentsEth1 = R"([Match]
368Name=eth1
369
370[Network]
371Bridge=br0
Tomáš Peckabd43a942021-08-04 10:12:49 +0200372IPv6AcceptRA=false
Tomáš Peckac2929a62021-06-05 17:21:03 +0200373DHCP=no
374LLDP=true
375EmitLLDP=nearest-bridge
376)";
377
378 // create br0 bridge over eth0 and eth1 with no IP
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100379 client.setItem("/ietf-interfaces:interfaces/interface[name='br0']/enabled", "false");
380 client.setItem("/ietf-interfaces:interfaces/interface[name='br0']/type", "iana-if-type:bridge");
Tomáš Peckac2929a62021-06-05 17:21:03 +0200381
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100382 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/type", "iana-if-type:ethernetCsmacd");
383 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/czechlight-network:bridge", "br0");
384 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:enabled", "false");
385 client.deleteItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4");
Tomáš Peckac2929a62021-06-05 17:21:03 +0200386
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100387 client.setItem("/ietf-interfaces:interfaces/interface[name='eth1']/type", "iana-if-type:ethernetCsmacd");
388 client.setItem("/ietf-interfaces:interfaces/interface[name='eth1']/czechlight-network:bridge", "br0");
389 client.setItem("/ietf-interfaces:interfaces/interface[name='eth1']/ietf-ip:ipv4/ietf-ip:enabled", "false");
390 client.deleteItem("/ietf-interfaces:interfaces/interface[name='eth1']/ietf-ip:ipv6");
Tomáš Peckac2929a62021-06-05 17:21:03 +0200391
392 REQUIRE_CALL(fake, cb(std::vector<std::string>{"br0", "eth0", "eth1"})).IN_SEQUENCE(seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100393 client.applyChanges();
Tomáš Peckac2929a62021-06-05 17:21:03 +0200394 REQUIRE(std::filesystem::exists(expectedFilePathBr0));
395 REQUIRE(std::filesystem::exists(expectedFilePathEth0));
396 REQUIRE(std::filesystem::exists(expectedFilePathEth1));
397 REQUIRE(velia::utils::readFileToString(expectedFilePathBr0) == expectedContentsBr0);
398 REQUIRE(velia::utils::readFileToString(expectedFilePathEth0) == expectedContentsEth0);
399 REQUIRE(velia::utils::readFileToString(expectedFilePathEth1) == expectedContentsEth1);
400
401 // assign an IPv4 address to br0
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100402 client.setItem("/ietf-interfaces:interfaces/interface[name='br0']/enabled", "true");
403 client.setItem("/ietf-interfaces:interfaces/interface[name='br0']/ietf-ip:ipv4/ietf-ip:address[ip='192.0.2.1']/ietf-ip:prefix-length", "24");
404 client.setItem("/ietf-interfaces:interfaces/interface[name='br0']/ietf-ip:ipv4/czechlight-network:dhcp-client", "false");
Tomáš Peckac2929a62021-06-05 17:21:03 +0200405 expectedContentsBr0 = R"([Match]
406Name=br0
407
408[Network]
409Address=192.0.2.1/24
410LinkLocalAddressing=no
Tomáš Peckabd43a942021-08-04 10:12:49 +0200411IPv6AcceptRA=false
Tomáš Peckac2929a62021-06-05 17:21:03 +0200412DHCP=no
413LLDP=true
414EmitLLDP=nearest-bridge
415)";
416
417 REQUIRE_CALL(fake, cb(std::vector<std::string>{"br0"})).IN_SEQUENCE(seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100418 client.applyChanges();
Tomáš Peckac2929a62021-06-05 17:21:03 +0200419 REQUIRE(std::filesystem::exists(expectedFilePathBr0));
420 REQUIRE(std::filesystem::exists(expectedFilePathEth0));
421 REQUIRE(std::filesystem::exists(expectedFilePathEth1));
422 REQUIRE(velia::utils::readFileToString(expectedFilePathBr0) == expectedContentsBr0);
423 REQUIRE(velia::utils::readFileToString(expectedFilePathEth0) == expectedContentsEth0);
424 REQUIRE(velia::utils::readFileToString(expectedFilePathEth1) == expectedContentsEth1);
425
426 // assign also an IPv6 address to br0
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100427 client.setItem("/ietf-interfaces:interfaces/interface[name='br0']/ietf-ip:ipv6/ietf-ip:address[ip='2001:db8::1']/ietf-ip:prefix-length", "32");
Tomáš Peckac2929a62021-06-05 17:21:03 +0200428 expectedContentsBr0 = R"([Match]
429Name=br0
430
431[Network]
432Address=192.0.2.1/24
433Address=2001:db8::1/32
Tomáš Peckabd43a942021-08-04 10:12:49 +0200434IPv6AcceptRA=true
Tomáš Peckac2929a62021-06-05 17:21:03 +0200435DHCP=no
436LLDP=true
437EmitLLDP=nearest-bridge
438)";
439
440 REQUIRE_CALL(fake, cb(std::vector<std::string>{"br0"})).IN_SEQUENCE(seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100441 client.applyChanges();
Tomáš Peckac2929a62021-06-05 17:21:03 +0200442 REQUIRE(std::filesystem::exists(expectedFilePathBr0));
443 REQUIRE(std::filesystem::exists(expectedFilePathEth0));
444 REQUIRE(std::filesystem::exists(expectedFilePathEth1));
445 REQUIRE(velia::utils::readFileToString(expectedFilePathBr0) == expectedContentsBr0);
446 REQUIRE(velia::utils::readFileToString(expectedFilePathEth0) == expectedContentsEth0);
447 REQUIRE(velia::utils::readFileToString(expectedFilePathEth1) == expectedContentsEth1);
448
449 // remove eth1 from bridge
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100450 client.deleteItem("/ietf-interfaces:interfaces/interface[name='eth1']/czechlight-network:bridge");
451 client.setItem("/ietf-interfaces:interfaces/interface[name='eth1']/ietf-ip:ipv6/ietf-ip:address[ip='2001:db8::2']/ietf-ip:prefix-length", "32");
Tomáš Peckac2929a62021-06-05 17:21:03 +0200452
453 expectedContentsEth1 = R"([Match]
454Name=eth1
455
456[Network]
457Address=2001:db8::2/32
Tomáš Peckabd43a942021-08-04 10:12:49 +0200458IPv6AcceptRA=true
Tomáš Peckac2929a62021-06-05 17:21:03 +0200459DHCP=no
460LLDP=true
461EmitLLDP=nearest-bridge
462)";
463
464 REQUIRE_CALL(fake, cb(std::vector<std::string>{"eth1"})).IN_SEQUENCE(seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100465 client.applyChanges();
Tomáš Peckac2929a62021-06-05 17:21:03 +0200466 REQUIRE(std::filesystem::exists(expectedFilePathBr0));
467 REQUIRE(std::filesystem::exists(expectedFilePathEth0));
468 REQUIRE(std::filesystem::exists(expectedFilePathEth1));
469 REQUIRE(velia::utils::readFileToString(expectedFilePathBr0) == expectedContentsBr0);
470 REQUIRE(velia::utils::readFileToString(expectedFilePathEth0) == expectedContentsEth0);
471 REQUIRE(velia::utils::readFileToString(expectedFilePathEth1) == expectedContentsEth1);
472
473 // reset the contents
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100474 client.deleteItem("/ietf-interfaces:interfaces/interface[name='br0']");
475 client.deleteItem("/ietf-interfaces:interfaces/interface[name='eth0']");
476 client.deleteItem("/ietf-interfaces:interfaces/interface[name='eth1']");
Tomáš Peckac2929a62021-06-05 17:21:03 +0200477 REQUIRE_CALL(fake, cb(std::vector<std::string>{"br0", "eth0", "eth1"})).IN_SEQUENCE(seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100478 client.applyChanges();
Tomáš Peckac2929a62021-06-05 17:21:03 +0200479 REQUIRE(!std::filesystem::exists(expectedFilePathBr0));
480 REQUIRE(!std::filesystem::exists(expectedFilePathEth0));
481 REQUIRE(!std::filesystem::exists(expectedFilePathEth1));
482 }
483
484 SECTION("Slave interface and enabled/disabled IP protocols")
485 {
486 const auto expectedFilePathBr0 = fakeConfigDir / "br0.network";
487 const auto expectedFilePathEth0 = fakeConfigDir / "eth0.network";
488
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100489 client.setItem("/ietf-interfaces:interfaces/interface[name='br0']/type", "iana-if-type:bridge");
490 client.setItem("/ietf-interfaces:interfaces/interface[name='br0']/ietf-ip:ipv4/ietf-ip:address[ip='192.0.2.1']/ietf-ip:prefix-length", "24");
491 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/type", "iana-if-type:ethernetCsmacd");
492 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/czechlight-network:bridge", "br0");
Tomáš Peckac2929a62021-06-05 17:21:03 +0200493
494 SECTION("Can't be a slave when IPv4 enabled")
495 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100496 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:address[ip='192.0.2.1']/ietf-ip:prefix-length", "24");
497 REQUIRE_THROWS_AS(client.applyChanges(), sysrepo::ErrorWithCode);
Tomáš Peckac2929a62021-06-05 17:21:03 +0200498 }
499
500 SECTION("Can't be a slave when IPv6 enabled")
501 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100502 client.setItem("/ietf-interfaces:interfaces/interface[name='eth1']/ietf-ip:ipv6/ietf-ip:address[ip='2001:db8::1']/ietf-ip:prefix-length", "32");
503 REQUIRE_THROWS_AS(client.applyChanges(), sysrepo::ErrorWithCode);
Tomáš Peckac2929a62021-06-05 17:21:03 +0200504 }
505
506 SECTION("Can't be a slave when both IPv4 and IPv6 enabled")
507 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100508 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:address[ip='192.0.2.1']/ietf-ip:prefix-length", "24");
509 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:address[ip='2001:db8::1']/ietf-ip:prefix-length", "32");
510 REQUIRE_THROWS_AS(client.applyChanges(), sysrepo::ErrorWithCode);
Tomáš Peckac2929a62021-06-05 17:21:03 +0200511 }
512
513 SECTION("Can be a slave when addresses present but protocol is disabled")
514 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100515 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:address[ip='192.0.2.1']/ietf-ip:prefix-length", "24");
516 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/enabled", "false");
Tomáš Peckac2929a62021-06-05 17:21:03 +0200517
518 REQUIRE_CALL(fake, cb(std::vector<std::string>{"br0", "eth0"})).IN_SEQUENCE(seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100519 client.applyChanges();
Tomáš Peckac2929a62021-06-05 17:21:03 +0200520
521 // reset the contents
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100522 client.deleteItem("/ietf-interfaces:interfaces/interface[name='br0']");
523 client.deleteItem("/ietf-interfaces:interfaces/interface[name='eth0']");
Tomáš Peckac2929a62021-06-05 17:21:03 +0200524 REQUIRE_CALL(fake, cb(std::vector<std::string>{"br0", "eth0"})).IN_SEQUENCE(seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100525 client.applyChanges();
Tomáš Peckac2929a62021-06-05 17:21:03 +0200526 REQUIRE(!std::filesystem::exists(expectedFilePathBr0));
527 REQUIRE(!std::filesystem::exists(expectedFilePathEth0));
528 }
529 }
Tomáš Peckabd43a942021-08-04 10:12:49 +0200530
531 SECTION("Network autoconfiguration")
532 {
533 const auto expectedFilePath = fakeConfigDir / "eth0.network";
534
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100535 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/type", "iana-if-type:ethernetCsmacd");
Tomáš Peckabd43a942021-08-04 10:12:49 +0200536
537 SECTION("IPv4 on with address, IPv6 disabled, DHCPv4 off, RA off")
538 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100539 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/czechlight-network:dhcp-client", "false");
540 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:address[ip='192.0.2.1']/ietf-ip:prefix-length", "24"); // in case DHCP is disabled an IP must be present
Tomáš Peckabd43a942021-08-04 10:12:49 +0200541
542 expectedContents = R"([Match]
543Name=eth0
544
545[Network]
546Address=192.0.2.1/24
547LinkLocalAddressing=no
548IPv6AcceptRA=false
549DHCP=no
550LLDP=true
551EmitLLDP=nearest-bridge
552)";
553 }
554
555 SECTION("IPv4 on with address, IPv6 disabled, DHCPv4 on, RA on")
556 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100557 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/czechlight-network:dhcp-client", "true");
558 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:address[ip='192.0.2.1']/ietf-ip:prefix-length", "24"); // in case DHCP is disabled an IP must be present
559 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:enabled", "false");
560 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:autoconf/ietf-ip:create-global-addresses", "true");
Tomáš Peckabd43a942021-08-04 10:12:49 +0200561
562 expectedContents = R"([Match]
563Name=eth0
564
565[Network]
566Address=192.0.2.1/24
567LinkLocalAddressing=no
568IPv6AcceptRA=false
569DHCP=ipv4
570LLDP=true
571EmitLLDP=nearest-bridge
572)";
573 }
574
575 SECTION("IPv4 disabled, IPv6 enabled, DHCPv4 on, RA on")
576 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100577 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:enabled", "false");
578 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/czechlight-network:dhcp-client", "true");
579 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:enabled", "true");
580 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:autoconf/ietf-ip:create-global-addresses", "true");
Tomáš Peckabd43a942021-08-04 10:12:49 +0200581
582 expectedContents = R"([Match]
583Name=eth0
584
585[Network]
586IPv6AcceptRA=true
587DHCP=no
588LLDP=true
589EmitLLDP=nearest-bridge
590)";
591 }
592
593 SECTION("IPv4 enabled, IPv6 enabled, DHCPv4 on, RA on")
594 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100595 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:enabled", "true");
596 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/czechlight-network:dhcp-client", "true");
597 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:enabled", "true");
598 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:autoconf/ietf-ip:create-global-addresses", "true");
Tomáš Peckabd43a942021-08-04 10:12:49 +0200599
600 expectedContents = R"([Match]
601Name=eth0
602
603[Network]
604IPv6AcceptRA=true
605DHCP=ipv4
606LLDP=true
607EmitLLDP=nearest-bridge
608)";
609 }
610
611 SECTION("IPv4 enabled, IPv6 enabled, DHCPv4 off, RA on")
612 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100613 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:enabled", "true");
614 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:address[ip='192.0.2.1']/prefix-length", "24");
615 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/czechlight-network:dhcp-client", "false");
616 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:enabled", "true");
617 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:autoconf/ietf-ip:create-global-addresses", "true");
Tomáš Peckabd43a942021-08-04 10:12:49 +0200618
619 expectedContents = R"([Match]
620Name=eth0
621
622[Network]
623Address=192.0.2.1/24
624IPv6AcceptRA=true
625DHCP=no
626LLDP=true
627EmitLLDP=nearest-bridge
628)";
629 }
630
631 SECTION("IPv4 disabled, IPv6 disabled, DHCPv4 off, RA off")
632 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100633 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/ietf-ip:address[ip='192.0.2.1']/prefix-length", "24");
634 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv4/czechlight-network:dhcp-client", "false");
635 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:address[ip='2001:db8::1']/prefix-length", "32");
636 client.setItem("/ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ietf-ip:autoconf/ietf-ip:create-global-addresses", "false");
Tomáš Peckabd43a942021-08-04 10:12:49 +0200637
638 expectedContents = R"([Match]
639Name=eth0
640
641[Network]
642Address=192.0.2.1/24
643Address=2001:db8::1/32
644IPv6AcceptRA=false
645DHCP=no
646LLDP=true
647EmitLLDP=nearest-bridge
648)";
649 }
650
651 REQUIRE_CALL(fake, cb(std::vector<std::string>{"eth0"})).IN_SEQUENCE(seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100652 client.applyChanges();
Tomáš Peckabd43a942021-08-04 10:12:49 +0200653 REQUIRE(std::filesystem::exists(expectedFilePath));
654 REQUIRE(velia::utils::readFileToString(expectedFilePath) == expectedContents);
655
656 // reset the contents
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100657 client.deleteItem("/ietf-interfaces:interfaces/interface[name='eth0']");
Tomáš Peckabd43a942021-08-04 10:12:49 +0200658 REQUIRE_CALL(fake, cb(std::vector<std::string>{"eth0"})).IN_SEQUENCE(seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100659 client.applyChanges();
Tomáš Peckabd43a942021-08-04 10:12:49 +0200660 REQUIRE(!std::filesystem::exists(expectedFilePath));
661 }
Tomáš Pecka39bbb512021-05-23 22:07:22 +0200662}