STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
test_board_net.cpp
Go to the documentation of this file.
1/**
2 * Board networking unit tests
3 *
4 * Includes the REAL header (common/board_net.h) rather than a replica: the
5 * point of this suite is that the board's working address and ID come only
6 * from the server, and a replica could not prove that about the shipped code.
7 * The stubbed EthernetClass records what gets written to the chip.
8 */
9
10// Match the LC / Actuator builds.
11#define SENSOR_ETH_USE_DHCP
12
13#include <unity.h>
14
15#include "board_net.h"
16
17static const byte kMac[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0x2A, 0x3C};
18
19static const IPAddress kGateway(0, 0, 0, 0);
20static const IPAddress kDns(192, 168, 2, 1);
21static const IPAddress kDefaultServer(192, 168, 2, 20);
22static const IPAddress kLeasedIP(192, 168, 2, 137);
23// 169.254.<1 + 0x2A % 254>.<0x3C>
24static const IPAddress kRecoveryIP(169, 254, 43, 60);
25
27 Ethernet.reset();
28 stub_set_millis(1000);
31 return s;
32}
33
36 Ethernet.dhcp_should_succeed = false;
38 return s;
39}
40
41// ---------------------------------------------------------------------------
42// The board asks; the server's answer is its address and its ID
43// ---------------------------------------------------------------------------
46 Ethernet.dhcp_should_succeed = true;
47 Ethernet.dhcp_assigned = kLeasedIP;
48
50
51 TEST_ASSERT_EQUAL_INT((int)BoardNet::AddressSource::Dhcp, (int)src);
52 TEST_ASSERT_TRUE(BoardNet::usingDhcp(s));
53 TEST_ASSERT_TRUE(Ethernet.localIP() == kLeasedIP);
54 // Nothing static was configured: the server's answer is the whole story.
55 TEST_ASSERT_EQUAL_INT(0, Ethernet.static_begin_calls);
56}
57
60 Ethernet.dhcp_should_succeed = true;
61 Ethernet.dhcp_assigned = IPAddress(192, 168, 2, 31);
63 TEST_ASSERT_EQUAL_UINT8(31, BoardNet::boardId(s));
64}
65
66// ---------------------------------------------------------------------------
67// No DHCP answer: the MAC-derived recovery address, reflash only
68// ---------------------------------------------------------------------------
70 // The vectors firmware/tools/ota_upload.py and daq-server's config
71 // validation test too; change one, change all three.
72 const byte rtd[6] = {0x4a, 0x27, 0xe2, 0x3a, 0xad, 0x71};
73 TEST_ASSERT_TRUE(BoardNet::recoveryAddress(rtd) ==
74 IPAddress(169, 254, 174, 113));
75 // Third octet stays in 1..254 (RFC 3927): 0x00 -> 1, 0xFE -> 1, 0xFF -> 2.
76 const byte lo[6] = {0, 0, 0, 0, 0x00, 0x00};
77 const byte fe[6] = {0, 0, 0, 0, 0xFE, 0xFF};
78 const byte ff[6] = {0, 0, 0, 0, 0xFF, 0x01};
79 TEST_ASSERT_TRUE(BoardNet::recoveryAddress(lo) ==
80 IPAddress(169, 254, 1, 0));
81 TEST_ASSERT_TRUE(BoardNet::recoveryAddress(fe) ==
82 IPAddress(169, 254, 1, 255));
83 TEST_ASSERT_TRUE(BoardNet::recoveryAddress(ff) ==
84 IPAddress(169, 254, 2, 1));
85}
86
89
90 TEST_ASSERT_EQUAL_INT((int)BoardNet::AddressSource::Recovery,
91 (int)s.source);
92 TEST_ASSERT_FALSE(BoardNet::usingDhcp(s));
93 TEST_ASSERT_TRUE(Ethernet.static_ip == kRecoveryIP);
94 TEST_ASSERT_TRUE(Ethernet.static_subnet == IPAddress(255, 255, 0, 0));
95 TEST_ASSERT_TRUE(Ethernet.localIP() == kRecoveryIP);
96 // Never a working 192.168.2.x address the board made up for itself.
97 TEST_ASSERT_FALSE(Ethernet.localIP()[0] == 192);
98 // And no identity: only the server gives one.
99 TEST_ASSERT_EQUAL_UINT8(0, BoardNet::boardId(s));
100}
101
104 TEST_ASSERT_EQUAL_INT((int)BoardNet::AddressSource::None, (int)s.source);
105 TEST_ASSERT_FALSE(BoardNet::hasAddress(s));
106
107 Ethernet.dhcp_should_succeed = true;
108 Ethernet.dhcp_assigned = kLeasedIP;
110 // The operator has to be able to tell an assigned address from recovery.
111 TEST_ASSERT_EQUAL_STRING("DHCP (assigned by the server)",
113}
114
115// ---------------------------------------------------------------------------
116// On the recovery address the board keeps asking
117// ---------------------------------------------------------------------------
120 const int asked = Ethernet.dhcp_begin_calls;
121
123 TEST_ASSERT_FALSE(BoardNet::retryDhcp(s, kDns, kGateway));
124 TEST_ASSERT_EQUAL_INT(asked, Ethernet.dhcp_begin_calls);
125}
126
129 const int asked = Ethernet.dhcp_begin_calls;
130
132 TEST_ASSERT_FALSE(BoardNet::retryDhcp(s, kDns, kGateway));
133
134 TEST_ASSERT_EQUAL_INT(asked + 1, Ethernet.dhcp_begin_calls);
135 // The failed attempt zeroed the address; the recovery one is back.
136 TEST_ASSERT_TRUE(Ethernet.localIP() == kRecoveryIP);
137 TEST_ASSERT_EQUAL_INT((int)BoardNet::AddressSource::Recovery,
138 (int)s.source);
139}
140
143 Ethernet.dhcp_should_succeed = true;
144 Ethernet.dhcp_assigned = IPAddress(192, 168, 2, 22);
145
147 TEST_ASSERT_TRUE(BoardNet::retryDhcp(s, kDns, kGateway));
148
149 TEST_ASSERT_TRUE(BoardNet::usingDhcp(s));
150 TEST_ASSERT_TRUE(Ethernet.localIP() == IPAddress(192, 168, 2, 22));
151 TEST_ASSERT_EQUAL_UINT8(22, BoardNet::boardId(s));
152
153 // On a lease, no more asking.
154 const int asked = Ethernet.dhcp_begin_calls;
156 TEST_ASSERT_FALSE(BoardNet::retryDhcp(s, kDns, kGateway));
157 TEST_ASSERT_EQUAL_INT(asked, Ethernet.dhcp_begin_calls);
158}
159
163 const int asked = Ethernet.dhcp_begin_calls;
164
165 // Reflashing on the recovery address is the point of it: never move the
166 // address out from under the transfer.
168 TEST_ASSERT_FALSE(BoardNet::retryDhcp(s, kDns, kGateway));
169 TEST_ASSERT_EQUAL_INT(asked, Ethernet.dhcp_begin_calls);
170}
171
172// ---------------------------------------------------------------------------
173// Lease renewal
174// ---------------------------------------------------------------------------
177 Ethernet.dhcp_should_succeed = true;
178 Ethernet.dhcp_assigned = kLeasedIP;
180
182 TEST_ASSERT_EQUAL_INT(1, Ethernet.maintain_calls);
183
184 // On the recovery address there is no lease to renew.
186 Ethernet.maintain_calls = 0;
188 TEST_ASSERT_EQUAL_INT(0, Ethernet.maintain_calls);
189}
190
193 Ethernet.dhcp_should_succeed = true;
194 Ethernet.dhcp_assigned = kLeasedIP;
196
197 // A renewal that moved our address mid-flash would drop the transfer.
199 Ethernet.maintain_calls = 0;
201 TEST_ASSERT_EQUAL_INT(0, Ethernet.maintain_calls);
202}
203
204// ---------------------------------------------------------------------------
205// Server discovery — separate from addressing, and still ours to do
206// ---------------------------------------------------------------------------
209 IPAddress server = kDefaultServer;
210
211 stub_set_millis(4000);
212 bool changed =
213 BoardNet::onServerPacket(s, IPAddress(192, 168, 2, 77), server);
214
215 TEST_ASSERT_TRUE(changed);
216 TEST_ASSERT_TRUE(s.serverLearned);
217 TEST_ASSERT_EQUAL_UINT32(4000, s.lastServerPacketMillis);
218 TEST_ASSERT_TRUE(server == IPAddress(192, 168, 2, 77));
219}
220
227
230 Ethernet.dhcp_should_succeed = true;
231 Ethernet.dhcp_assigned = kLeasedIP;
233 int writes = Ethernet.set_local_ip_calls;
234
235 IPAddress server = kDefaultServer;
236 BoardNet::onServerPacket(s, IPAddress(169, 254, 130, 5), server);
237
238 // Hearing from a server on some other subnet is not a reason to re-address
239 // ourselves — only the DHCP server gets to decide where we live.
240 TEST_ASSERT_EQUAL_INT(writes, Ethernet.set_local_ip_calls);
241 TEST_ASSERT_TRUE(Ethernet.localIP() == kLeasedIP);
242}
243
249
261
262// ---------------------------------------------------------------------------
263// The MAC the server keys its reservation table on
264// ---------------------------------------------------------------------------
267 TEST_ASSERT_EQUAL_UINT8(0xDE, s.mac[0]);
268 TEST_ASSERT_EQUAL_UINT8(0x3C, s.mac[5]);
269 // printMac() goes to the stubbed Serial; this just proves it is callable
270 // and reads the configured MAC rather than anything else.
272}
273
274void setUp(void) {
275}
276void tearDown(void) {
277}
278
279int main(int, char**) {
280 UNITY_BEGIN();
281
282 // addressing
288
289 // retry on the recovery address
294
295 // lease renewal
298
299 // server discovery
305
306 // identity
308
309 return UNITY_END();
310}
void stub_set_millis(unsigned long v)
Definition Arduino.h:32
static EthernetClass Ethernet
Definition Ethernet.h:116
const int IPAddress
#define SENSOR_ZEROCONF_SERVER_SILENCE_MS
#define SENSOR_ETH_DHCP_RETRY_INTERVAL_MS
void configure(State &s, const byte mac[6])
Definition board_net.h:93
AddressSource begin(State &s, IPAddress dns, IPAddress gateway)
Bring the interface up: ask the ground station for an address, and take the recovery address only if ...
Definition board_net.h:181
void printMac(const State &s)
Print the MAC as aa:bb:cc:dd:ee:ff.
Definition board_net.h:103
IPAddress recoveryAddress(const byte mac[6])
The board's recovery address, from its MAC: 169.254.
Definition board_net.h:77
uint8_t boardId(const State &s)
The board's ID: the last octet of the address the server assigned (192.168.2.31 -> 31).
Definition board_net.h:129
void beginOtaHold(State &s)
Called when an OTA transfer starts, so the address cannot move under it.
Definition board_net.h:144
bool retryDhcp(State &s, IPAddress dns, IPAddress gateway)
On the recovery address, ask for a lease again every SENSOR_ETH_DHCP_RETRY_INTERVAL_MS.
Definition board_net.h:213
bool usingDhcp(const State &s)
Definition board_net.h:116
bool serverWentSilent(const State &s)
Server has stopped talking — forget it and resume discovery broadcasts.
Definition board_net.h:166
AddressSource
How the board ended up with the address it is using.
Definition board_net.h:46
@ None
not yet brought up
Definition board_net.h:47
@ Recovery
no DHCP answer: 169.254.x.y from the MAC, reflash-only
Definition board_net.h:49
@ Dhcp
assigned by the ground station — the normal case
Definition board_net.h:48
bool onServerPacket(State &s, IPAddress remote_ip, IPAddress &serverIP)
A server packet arrived from remote_ip; adopt it as the server address.
Definition board_net.h:152
void maintainLease(State &s)
Renew the lease as it expires.
Definition board_net.h:138
bool hasAddress(const State &s)
Definition board_net.h:120
const char * sourceName(AddressSource s)
Definition board_net.h:52
bool serverLearned
server IP adopted from an inbound packet
Definition board_net.h:87
unsigned long lastServerPacketMillis
Definition board_net.h:89
AddressSource source
Definition board_net.h:86
int main()
static const IPAddress kDns(192, 168, 2, 1)
static const IPAddress kGateway(0, 0, 0, 0)
static const IPAddress kRecoveryIP(169, 254, 43, 60)
static BoardNet::State recoveringState()
void test_no_retry_during_an_ota(void)
void test_retry_waits_for_the_interval(void)
void test_lease_is_renewed_only_on_a_lease(void)
static const IPAddress kDefaultServer(192, 168, 2, 20)
void test_ota_suspends_renewal(void)
void test_server_silence_trips_after_timeout(void)
static BoardNet::State makeState()
void test_recovery_address_formula(void)
void test_mac_is_stored_for_reporting(void)
void test_no_answer_puts_the_board_on_its_recovery_address(void)
void test_repeat_server_packet_is_not_a_change(void)
void test_dhcp_lease_is_adopted(void)
void test_server_silence_only_after_it_was_learned(void)
void test_learning_a_server_never_moves_our_address(void)
void setUp(void)
void tearDown(void)
void test_board_id_is_the_assigned_address(void)
void test_source_is_reported_honestly(void)
void test_retry_that_gets_a_lease_moves_the_board(void)
static const IPAddress kLeasedIP(192, 168, 2, 137)
static const byte kMac[6]
void test_server_is_learned_from_its_packets(void)
void test_failed_retry_stays_reflashable(void)