A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-tx-stats-helper-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2024 Huazhong University of Science and Technology
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Muyuan Shen <muyuan@uw.edu>
7 */
8
9#include "ns3/ap-wifi-mac.h"
10#include "ns3/boolean.h"
11#include "ns3/config.h"
12#include "ns3/eht-configuration.h"
13#include "ns3/log.h"
14#include "ns3/mobility-helper.h"
15#include "ns3/multi-model-spectrum-channel.h"
16#include "ns3/packet-socket-client.h"
17#include "ns3/packet-socket-helper.h"
18#include "ns3/packet-socket-server.h"
19#include "ns3/packet.h"
20#include "ns3/pointer.h"
21#include "ns3/qos-txop.h"
22#include "ns3/qos-utils.h"
23#include "ns3/rng-seed-manager.h"
24#include "ns3/single-model-spectrum-channel.h"
25#include "ns3/spectrum-wifi-helper.h"
26#include "ns3/string.h"
27#include "ns3/test.h"
28#include "ns3/wifi-mac-header.h"
29#include "ns3/wifi-mac.h"
30#include "ns3/wifi-net-device.h"
31#include "ns3/wifi-ppdu.h"
32#include "ns3/wifi-psdu.h"
33#include "ns3/wifi-tx-stats-helper.h"
34
35#include <vector>
36
37using namespace ns3;
38
39NS_LOG_COMPONENT_DEFINE("WifiTxStatsHelperTest");
40
41/**
42 * @ingroup wifi-test
43 * @brief Implements a test case to evaluate the transmission process of multiple Wi-Fi
44 * MAC Layer MPDUs. The testcase has two options.
45 * 1) SINGLE_LINK_NON_QOS: test the handling of regular ACKs.
46 * 2) MULTI_LINK_QOS: test the handling of MPDU aggregation, Block ACKs, and Multi-Link Operation.
47 *
48 * To observe the operation of WifiTxStatsHelper, the test can be run from the command line as
49 * follows:
50 * @code
51 * NS_LOG="WifiTxStatsHelper=level_info|prefix_all" ./ns3 run 'test-runner
52 * --suite=wifi-tx-stats-helper'
53 * @endcode
54 */
56{
57 public:
58 /**
59 * Option for the test
60 */
66
67 /**
68 * Constructor
69 * @param testName Test name
70 * @param option Test option
71 */
72 WifiTxStatsHelperTest(const std::string& testName, TestOption option);
73
74 /**
75 * Callback invoked when PHY starts transmission of a PSDU, used to record TX start
76 * time and TX duration.
77 *
78 * @param context the context
79 * @param psduMap the PSDU map
80 * @param txVector the TX vector
81 * @param txPower the tx power in Watts
82 */
83 void Transmit(std::string context,
84 WifiConstPsduMap psduMap,
85 WifiTxVector txVector,
86 Watt_u txPower);
87
88 private:
89 TestOption m_option; //!< Test option
90 NodeContainer m_wifiApNode; //!< NodeContainer for AP
91 NodeContainer m_wifiStaNodes; //!< NodeContainer for STAs
92 int64_t m_streamNumber; //!< Random variable stream number
93 Time m_sifs; //!< SIFS time
94 Time m_slot; //!< slot time
95
96 Time m_difs; //!< DIFS time (for SINGLE_LINK_NON_QOS case only)
97 std::map<uint8_t, std::vector<Time>> m_txStartTimes; //!< Map of independently obtain vector of
98 //!< PhyTxBegin trace, indexed per link
99 std::map<uint8_t, std::vector<Time>>
100 m_durations; //!< Map of vector of MPDU durations, indexed per link
101 std::map<uint8_t, uint32_t> m_cwMins; //!< Map of CW Mins, indexed per link
102 std::map<uint8_t, uint32_t>
103 m_aifsns; //!< Map of AIFSNs, indexed per link (for MULTI_LINK_QOS case only)
104 std::map<uint8_t, Time>
105 m_aifss; //!< Map of AIFSs, indexed per link (for MULTI_LINK_QOS case only)
106
107 void DoSetup() override;
108 void DoRun() override;
109 /**
110 * Check correctness of test
111 * @param wifiTxStats Reference to the helper
112 */
113 void CheckResults(const WifiTxStatsHelper& wifiTxStats);
114};
115
117 : TestCase(testName),
118 m_option(option),
119 m_streamNumber(100)
120{
121}
122
123void
125 WifiConstPsduMap psduMap,
126 WifiTxVector txVector,
127 Watt_u txPower)
128{
129 const auto linkId = atoi(context.c_str());
130 if (linkId == 0)
131 {
132 m_txStartTimes[0].push_back(Simulator::Now());
133 m_durations[0].push_back(
135 }
136 else if (linkId == 1)
137 {
138 m_txStartTimes[1].push_back(Simulator::Now());
139 m_durations[1].push_back(
141 }
142 NS_LOG_INFO("LINKID=" << +linkId << " " << *psduMap.cbegin()->second << "\n");
143}
144
145void
147{
150
151 m_wifiApNode.Create(1);
152 m_wifiStaNodes.Create(1);
153
154 MobilityHelper mobility;
155 auto positionAlloc = CreateObject<ListPositionAllocator>();
156 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
157 positionAlloc->Add(Vector(1.0, 0.0, 0.0));
158 mobility.SetPositionAllocator(positionAlloc);
159 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
160 mobility.Install(m_wifiApNode);
161 mobility.Install(m_wifiStaNodes);
162
163 PacketSocketHelper packetSocket;
164 packetSocket.Install(m_wifiApNode);
165 packetSocket.Install(m_wifiStaNodes);
166}
167
168void
170{
171 Config::SetDefault("ns3::WifiRemoteStationManager::IncrementRetryCountUnderBa",
172 BooleanValue(true));
173 std::string dataMode;
174 std::string ackMode;
176 {
177 dataMode = "OfdmRate12Mbps";
178 ackMode = "OfdmRate6Mbps";
179 }
180 else
181 {
182 dataMode = "EhtMcs6";
183 ackMode = "OfdmRate54Mbps";
184 }
185
186 WifiHelper wifi;
187 NetDeviceContainer staDevices;
188 NetDeviceContainer apDevices;
190 {
191 wifi.SetStandard(WIFI_STANDARD_80211a);
192 wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
193 "DataMode",
194 StringValue(dataMode),
195 "ControlMode",
196 StringValue(ackMode));
197 auto spectrumChannel = CreateObject<SingleModelSpectrumChannel>();
199 spectrumChannel->AddPropagationLossModel(lossModel);
201 spectrumChannel->SetPropagationDelayModel(delayModel);
202
204 phy.SetChannel(spectrumChannel);
205
206 WifiMacHelper mac;
207 mac.SetType("ns3::StaWifiMac",
208 "QosSupported",
209 BooleanValue(false),
210 "Ssid",
211 SsidValue(Ssid("test-ssid")));
212 staDevices = wifi.Install(phy, mac, m_wifiStaNodes);
213
214 mac.SetType("ns3::ApWifiMac",
215 "QosSupported",
216 BooleanValue(false),
217 "Ssid",
218 SsidValue(Ssid("test-ssid")),
219 "BeaconInterval",
220 TimeValue(MicroSeconds(102400)),
221 "EnableBeaconJitter",
222 BooleanValue(false));
223 apDevices = wifi.Install(phy, mac, m_wifiApNode);
224 }
225 else
226 {
227 wifi.SetStandard(WIFI_STANDARD_80211be);
228 // Get channel string for MLD STA
229 std::array<std::string, 2> mldChannelStr;
230 uint32_t frequency = 5;
231 uint32_t frequency2 = 6;
232 for (auto freq : {frequency, frequency2})
233 {
234 NS_TEST_ASSERT_MSG_EQ((freq == 5 || freq == 6), true, "Unsupported frequency for BSS");
235 if (freq == 6)
236 {
237 mldChannelStr[1] = "{0, 20, BAND_6GHZ, 0}";
238 uint8_t linkId = 1;
239 wifi.SetRemoteStationManager(linkId,
240 "ns3::ConstantRateWifiManager",
241 "DataMode",
242 StringValue(dataMode),
243 "ControlMode",
244 StringValue(ackMode));
245 }
246 else
247 {
248 mldChannelStr[0] = "{0, 20, BAND_5GHZ, 0}";
249 // linkId is passed as a variable here because MSVC
250 // interprets uint8_t as a char, and the 0 value as a
251 // c-string null terminator \0. This results into a
252 // compilation error due to SetRemoteStationManager(uint8_t,...)
253 // and SetRemoteStationManager(std::string, ...) signatures.
254 uint8_t linkId = 0;
255 wifi.SetRemoteStationManager(linkId,
256 "ns3::ConstantRateWifiManager",
257 "DataMode",
258 StringValue(dataMode),
259 "ControlMode",
260 StringValue(ackMode));
261 }
262 }
263
265
267 auto spectrumChannel1 = CreateObject<MultiModelSpectrumChannel>();
268 spectrumChannel1->AddPropagationLossModel(lossModel);
269 auto spectrumChannel2 = CreateObject<MultiModelSpectrumChannel>();
270 spectrumChannel2->AddPropagationLossModel(lossModel);
271
272 phy.AddChannel(spectrumChannel1, WIFI_SPECTRUM_5_GHZ);
273 phy.AddChannel(spectrumChannel2, WIFI_SPECTRUM_6_GHZ);
274
275 for (uint8_t linkId = 0; linkId < 2; ++linkId)
276 {
277 phy.Set(linkId, "ChannelSettings", StringValue(mldChannelStr[linkId]));
278 }
279
280 WifiMacHelper mac;
281 mac.SetType("ns3::StaWifiMac",
282 "QosSupported",
283 BooleanValue(true),
284 "Ssid",
285 SsidValue(Ssid("test-ssid")));
286 staDevices = wifi.Install(phy, mac, m_wifiStaNodes);
287
288 mac.SetType("ns3::ApWifiMac",
289 "QosSupported",
290 BooleanValue(true),
291 "Ssid",
292 SsidValue(Ssid("test-ssid")),
293 "BeaconInterval",
294 TimeValue(MicroSeconds(102400)),
295 "EnableBeaconJitter",
296 BooleanValue(false));
297 apDevices = wifi.Install(phy, mac, m_wifiApNode);
298 }
299
300 m_sifs = DynamicCast<WifiNetDevice>(apDevices.Get(0))->GetPhy()->GetSifs();
301 m_slot = DynamicCast<WifiNetDevice>(apDevices.Get(0))->GetPhy()->GetSlot();
303 {
304 m_difs = m_sifs + 2 * m_slot;
306 DynamicCast<WifiNetDevice>(apDevices.Get(0))->GetMac()->GetTxop()->GetMinCw();
307 }
308 else
309 {
310 // Use TID-to-link Mapping to tx TID=3 pkts (BE) only on link 0,
311 // TID=4 pkts (VI) only on link 1
312 m_cwMins[0] = 15;
313 m_cwMins[1] = 7;
314 m_aifsns[0] = 3;
315 m_aifsns[1] = 2;
316 m_aifss[0] = m_aifsns[0] * m_slot + m_sifs;
317 m_aifss[1] = m_aifsns[1] * m_slot + m_sifs;
318 std::string mldMappingStr = "3 0; 4 1";
319 DynamicCast<WifiNetDevice>(staDevices.Get(0))
320 ->GetMac()
321 ->GetEhtConfiguration()
322 ->SetAttribute("TidToLinkMappingUl", StringValue(mldMappingStr));
323 }
324
325 auto streamsUsed = WifiHelper::AssignStreams(apDevices, m_streamNumber);
326 NS_ASSERT_MSG(streamsUsed < 100, "Need to increment by larger quantity");
327 WifiHelper::AssignStreams(staDevices, m_streamNumber + 100);
328
329 // UL traffic (TX statistics will be installed at STA side)
330 PacketSocketAddress socket;
331 socket.SetSingleDevice(staDevices.Get(0)->GetIfIndex());
332 socket.SetPhysicalAddress(apDevices.Get(0)->GetAddress());
333 auto server = CreateObject<PacketSocketServer>();
334 server->SetLocal(socket);
335 m_wifiApNode.Get(0)->AddApplication(server);
336 server->SetStartTime(Seconds(0.0));
337 server->SetStopTime(Seconds(1.0));
339 {
340 auto client = CreateObject<PacketSocketClient>();
341 client->SetAttribute("PacketSize", UintegerValue(1500));
342 client->SetAttribute("MaxPackets", UintegerValue(3));
343 client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
344 client->SetRemote(socket);
345 m_wifiStaNodes.Get(0)->AddApplication(client);
346 client->SetStartTime(MicroSeconds(210000));
347 client->SetStopTime(Seconds(1.0));
348 }
349 else
350 {
351 auto clientBe = CreateObject<PacketSocketClient>();
352 clientBe->SetAttribute("Priority", UintegerValue(3));
353 clientBe->SetAttribute("PacketSize", UintegerValue(1500));
354 clientBe->SetAttribute("MaxPackets", UintegerValue(3));
355 clientBe->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
356 clientBe->SetRemote(socket);
357 m_wifiStaNodes.Get(0)->AddApplication(clientBe);
358 clientBe->SetStartTime(MicroSeconds(200000));
359 clientBe->SetStopTime(Seconds(1.0));
360
361 auto clientVi = CreateObject<PacketSocketClient>();
362 clientVi->SetAttribute("Priority", UintegerValue(4));
363 clientVi->SetAttribute("PacketSize", UintegerValue(1500));
364 clientVi->SetAttribute("MaxPackets", UintegerValue(3));
365 clientVi->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
366 clientVi->SetRemote(socket);
367 m_wifiStaNodes.Get(0)->AddApplication(clientVi);
368 clientVi->SetStartTime(MicroSeconds(300000));
369 clientVi->SetStopTime(Seconds(1.0));
370 }
371
372 // Add AP side receiver corruption
374 {
375 // We corrupt AP side reception so that:
376 // 1) the 2nd data frame is retransmitted and succeeds (1 failure, 1 success)
377 // 2) the 3rd data frame is transmitted 7 times (=FrameRetryLimit) and finally fails (7
378 // failures, 0 success)
379 //
380 // No. of pkt | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
381 // No. recvd by AP | | | 0 | | | 1 | | 2 | | AP's
382 // pkts | Bea | Bea | | Ack | AsRes | | Bea | | Ack1 |
383 // STA's pkts | | | AsReq | | | Ack | | Data1 | |
384 //
385 // No. of pkt | 9 | 10 | 11 | 12 | 13 | ... | 18 | 19 | ...
386 // No. recvd by AP | 3 (x) | 4 | | 5 (x) | 6 (x) | ... |11 (x) | | ...
387 // AP's pkts | | | Ack2 | | | ... | | Bea | ...
388 // STA's pkts | Data2 | Data2 | | Data3 | Data3 | ... | Data3 | | ...
389 //
390 // Legend:
391 // Bea = Beacon, AsReq = Association Request, AsRes = Association Response
392 // AP side corruption is indicated with (x)
393
395 apPem->SetList({3, 5, 6, 7, 8, 9, 10, 11});
396 DynamicCast<WifiNetDevice>(apDevices.Get(0))
397 ->GetMac()
398 ->GetWifiPhy()
399 ->SetPostReceptionErrorModel(apPem);
400 }
401 else
402 {
403 // We corrupt AP side reception so that:
404 // On Link 0 (contains uplink data with TID = 3):
405 // 1) the 2nd data frame is retransmitted once and succeeds (retransmission = 1)
406 // 2) the 3rd data frame is transmitted 2 times within A-MPDU and 7 times alone
407 // (WifiMac::FrameRetryLimit) and finally fails (retransmission = 8)
408 //
409 // No. of PSDU | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
410 // No. recvd by AP | | | 0 | | 1 | | 2 | | 3 |
411 // AP's pkts | Bea | Bea | | Ack | | AsRes | | CfEnd | |
412 // STA's pkts | | | AsReq | | CfEnd | | Ack | | ABReq
413 // |
414 //
415 // No. of PSDU | 9 | 10 | 11 | 12 | 12 | 12 | 13 | 14 | 14 |
416 // No. recvd by AP | | | 4 | 5 | 6(x) | 7(x) | | 8 | 9(x) |
417 // AP's pkts | Ack | ABRes | | | | | BAck | | |
418 // STA's pkts | | | Ack | Data1 | Data2 | Data3 | | Data2 | Data3
419 // |
420 //
421 // No. of PSDU | 15 | 16 | ... | | ... | 23 | 24 | 25 | ...
422 // No. recvd by AP | | 10(x) | ... | | ... | 16(x) | 17 | | ...
423 // AP's pkts | BAck | | ... | Bea | ... | | | BAck | ...
424 // STA's pkts | | Data3 | ... | | ... | Data3 | Bar | | ...
425 //
426 // On Link 1 (contains uplink data with TID = 4):
427 // 1) the 2nd data frame is transmitted 2 times within A-MPDU and 7 times alone
428 // (=WifiMac::FrameRetryLimit) and finally fails (retransmission = 8)
429 // 2) the 3rd data frame is
430 // retransmitted once and succeeds (retransmission = 1)
431 //
432 // No. of PSDU | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
433 // No. recvd by AP | | | 0 | | | 1 | | 2 | | AP's
434 // pkts | Bea | Bea | | Ack | Bea | | Ack | | ABRes |
435 // STA's pkts | | | Null | | | ABReq | | CfEnd | |
436 //
437 // No. of PSDU | 9 | 10 | 11 | 11 | 11 | 12 | 13 | 13 | 14 |
438 // No. recvd by AP | 3 | | 4 | 5(x) | 6(x) | | 7(x) | 8 | | AP's
439 // pkts | | CfEnd | | | | BAck | | | BAck |
440 // STA's pkts | Ack | | Data1 | Data2 | Data3 | | Data2 | Data3 | |
441 //
442 // No. of PSDU | 15 | ... | 21 | 22 | 23 | 24 | ...
443 // No. recvd by AP | 9(x) | ... | 15(x) | 16 | | 17 | ...
444 // AP's pkts | | ... | | | BAck | | ...
445 // STA's pkts | Data2 | ... | Data2 | Bar | | CfEnd | ...
446 //
447 // Legend:
448 // Bea = Beacon, AsReq = Association Request, AsRes = Association Response
449 // ABReq = Add Block ACK Request, ABRes = Add Block ACK Response
450 // Bar = Block ACK Request (used to notify the discarded MPDU)
451 // CfEnd = CF-End, BAck = Block ACK (Response), Null = Null function
452 // AP side corruption is indicated with (x)
453
454 // Force drops on link 0 at AP
456 apPem0->SetList({6, 7, 9, 10, 11, 12, 13, 14, 15, 16});
457 DynamicCast<WifiNetDevice>(apDevices.Get(0))
458 ->GetMac()
459 ->GetWifiPhy(0)
460 ->SetPostReceptionErrorModel(apPem0);
461
462 // Force drops on link 1 at AP
464 apPem1->SetList({5, 6, 7, 9, 10, 11, 12, 13, 14, 15});
465 DynamicCast<WifiNetDevice>(apDevices.Get(0))
466 ->GetMac()
467 ->GetWifiPhy(1)
468 ->SetPostReceptionErrorModel(apPem1);
469 }
470
471 NetDeviceContainer allNetDev;
472 allNetDev.Add(apDevices);
473 allNetDev.Add(staDevices);
474 WifiTxStatsHelper wifiTxStats;
475 wifiTxStats.Enable(allNetDev);
476 wifiTxStats.Start(Seconds(0));
477 wifiTxStats.Stop(Seconds(1));
478
479 // Trace PSDU TX at both AP and STA to get start times and durations, including acks
481 {
482 for (auto it = allNetDev.Begin(); it != allNetDev.End(); ++it)
483 {
484 auto dev = DynamicCast<WifiNetDevice>(*it);
485 dev->GetPhy()->TraceConnect("PhyTxPsduBegin",
486 std::to_string(SINGLE_LINK_OP_ID),
487 // "0"
489 }
490 }
491 else
492 {
493 for (auto it = allNetDev.Begin(); it != allNetDev.End(); ++it)
494 {
495 auto dev = DynamicCast<WifiNetDevice>(*it);
496 dev->GetPhy(0)->TraceConnect("PhyTxPsduBegin",
497 "0",
499 dev->GetPhy(1)->TraceConnect("PhyTxPsduBegin",
500 "1",
502 }
503 }
504
507 CheckResults(wifiTxStats);
509}
510
511void
513{
514 const auto tolerance = NanoSeconds(50); // due to propagation delay
515 // Check both variants of GetSuccesses...()
516 const auto successMap = wifiTxStats.GetSuccessesByNodeDevice();
517 const auto successMapPerNodeDeviceLink = wifiTxStats.GetSuccessesByNodeDeviceLink();
518 const auto failureMap = wifiTxStats.GetFailuresByNodeDevice();
519 const auto retransmissionMap = wifiTxStats.GetRetransmissionsByNodeDevice();
520 const auto totalSuccesses = wifiTxStats.GetSuccesses();
521 const auto totalFailures = wifiTxStats.GetFailures();
522 const auto totalRetransmissions = wifiTxStats.GetRetransmissions();
523 const auto& successRecords = wifiTxStats.GetSuccessRecords();
524 const auto& failureRecords = wifiTxStats.GetFailureRecords();
525
526 uint32_t nodeId = 1;
527 uint32_t deviceId = 0;
528 auto nodeDeviceTuple = std::make_tuple(nodeId, deviceId);
529 auto nodeDeviceLink0Tuple = std::make_tuple(nodeId, deviceId, 0);
530 auto nodeDeviceLink1Tuple = std::make_tuple(nodeId, deviceId, 1);
531
533 {
534 const auto totalFailuresDrop =
536 const auto totalFailuresDropMap = wifiTxStats.GetFailuresByNodeDevice(
538
539 NS_TEST_ASSERT_MSG_EQ(successMapPerNodeDeviceLink.at(nodeDeviceLink0Tuple),
540 2,
541 "Number of success packets should be 2");
542 NS_TEST_ASSERT_MSG_EQ(successMap.at(nodeDeviceTuple),
543 2,
544 "Number of success packets should be 2");
545 NS_TEST_ASSERT_MSG_EQ(totalSuccesses, 2, "Number of success packets should be 2");
546
547 NS_TEST_ASSERT_MSG_EQ(retransmissionMap.at(nodeDeviceTuple),
548 1,
549 "Number of retransmitted successful packets should be 1");
550 NS_TEST_ASSERT_MSG_EQ(totalRetransmissions,
551 1,
552 "Number of retransmitted successful packets should be 1");
553
554 NS_TEST_ASSERT_MSG_EQ(failureMap.at(nodeDeviceTuple),
555 1,
556 "Number of failed packets should be 1");
557 NS_TEST_ASSERT_MSG_EQ(totalFailures, 1, "Number of failed packets (aggregate) should be 1");
559 totalFailuresDrop,
560 1,
561 "Number of dropped packets (aggregate) due to retry limit reached should be 1");
563 totalFailuresDropMap.at(nodeDeviceTuple),
564 1,
565 "Number of dropped packets (aggregate) due to retry limit reached should be 1");
566
567 auto successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
568 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_nodeId,
569 1,
570 "Source node ID of the 1st successful data packet should be 1");
571 std::advance(successRecordIt, 1);
572 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_nodeId,
573 1,
574 "Source node ID of the 2nd successful data packet should be 1");
575 auto failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
576 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_nodeId,
577 1,
578 "Source node ID of the failed data packet should be 1");
579
580 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
582 successRecordIt->m_retransmissions,
583 0,
584 "The retransmission count of the 1st successful data packet should be 0");
585 std::advance(successRecordIt, 1);
587 successRecordIt->m_retransmissions,
588 1,
589 "The retransmission count of the 2nd successful data packet should be 1");
590 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_retransmissions,
591 6,
592 "The retransmission count of the failed data packet should be 6");
593
594 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
595 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_txStartTime.IsStrictlyPositive(),
596 true,
597 "The 1st successful data packet should have been TXed");
598 std::advance(successRecordIt, 1);
599 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_txStartTime.IsStrictlyPositive(),
600 true,
601 "The 2nd successful data packet should have been TXed");
602 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_txStartTime.IsStrictlyPositive(),
603 true,
604 "The failed data packet should have been TXed");
605
606 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
607 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_ackTime.IsStrictlyPositive(),
608 true,
609 "The 1st successful data packet should have been acked");
610 std::advance(successRecordIt, 1);
611 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_ackTime.IsStrictlyPositive(),
612 true,
613 "The 2nd successful data packet should have been acked");
614 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_ackTime.IsStrictlyPositive(),
615 false,
616 "The failed data packet should not have been acked");
617
618 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
619 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_ackTime.IsStrictlyPositive(),
620 true,
621 "The 1st successful data packet should have been dequeued");
622 std::advance(successRecordIt, 1);
623 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_ackTime.IsStrictlyPositive(),
624 true,
625 "The 2nd successful data packet should have been dequeued");
626 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.has_value() &&
627 failureRecordIt->m_dropTime.value().IsStrictlyPositive(),
628 true,
629 "The failed data packet should have been dequeued");
630
631 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
632 auto successRecordItNext = successRecordIt;
633 std::advance(successRecordItNext, 1);
634 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_enqueueTime,
635 successRecordItNext->m_enqueueTime,
636 "Three packets should be enqueued at the same time");
637 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_enqueueTime,
638 failureRecordIt->m_enqueueTime,
639 "Three packets should be enqueued at the same time");
640
641 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
642 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordIt->m_txStartTime,
643 successRecordIt->m_enqueueTime,
644 "Packets should be TXed after enqueued");
645 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordIt->m_txStartTime,
646 successRecordIt->m_enqueueTime + tolerance +
648 "Packet backoff slots should not exceed cwMin");
649 // Packet start time 7 corresponds to first data packet (prior to this, beacons and assoc)
650 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_txStartTime,
652 "Wrong TX start time");
653 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordIt->m_ackTime,
657 "Wrong Ack reception time");
658 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordIt->m_ackTime,
661 m_durations[SINGLE_LINK_OP_ID][8] + 2 * tolerance,
662 "Wrong Ack reception time");
663 std::advance(successRecordIt, 1);
664 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordIt->m_txStartTime,
667 "Packets should be TXed after enqueued");
668 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordIt->m_txStartTime,
670 m_durations[SINGLE_LINK_OP_ID][8] + m_difs + tolerance +
672 "Packet backoff slots should not exceed cwMin");
673 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_txStartTime,
675 "Wrong TX start time");
676 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordIt->m_ackTime,
680 "Wrong Ack reception time");
682 successRecordIt->m_ackTime,
685 ((m_cwMins[SINGLE_LINK_OP_ID] + 1) * 2 - 1) * m_slot + 2 * tolerance,
686 "Wrong Ack reception time");
687
688 NS_TEST_ASSERT_MSG_GT_OR_EQ(failureRecordIt->m_txStartTime,
691 "Packets should be TXed after enqueued");
692 NS_TEST_ASSERT_MSG_LT_OR_EQ(failureRecordIt->m_txStartTime,
694 m_durations[SINGLE_LINK_OP_ID][11] + m_difs + tolerance +
696 "Packet backoff slots should not exceed cwMin");
697 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_txStartTime,
699 "Wrong TX start time");
700 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.has_value() &&
701 failureRecordIt->m_dropReason.has_value(),
702 true,
703 "Missing drop time or reason");
704 NS_TEST_ASSERT_MSG_GT_OR_EQ(failureRecordIt->m_dropTime.value(),
707 "Wrong Dequeue time for failed packet");
708 NS_TEST_ASSERT_MSG_LT_OR_EQ(failureRecordIt->m_dropTime.value(),
712 "Wrong Dequeue time for failed packet");
713 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropReason.value(),
715 "Wrong drop reason");
716 }
717 else
718 {
719 const auto totalFailuresQos =
721 const auto totalFailuresQosMap =
723
724 for (std::vector<Time>::size_type i = 0; i < m_txStartTimes[0].size(); ++i)
725 {
726 NS_LOG_INFO("link 0 pkt " << i << " start tx at " << m_txStartTimes[0][i].As(Time::US));
727 }
728 for (std::vector<Time>::size_type i = 0; i < m_txStartTimes[1].size(); ++i)
729 {
730 NS_LOG_INFO("link 1 pkt " << i << " start tx at " << m_txStartTimes[1][i].As(Time::US));
731 }
732
733 NS_TEST_ASSERT_MSG_EQ(successMapPerNodeDeviceLink.at(nodeDeviceLink0Tuple),
734 2,
735 "Number of success packets on link 0 should be 2");
736 NS_TEST_ASSERT_MSG_EQ(successMapPerNodeDeviceLink.at(nodeDeviceLink1Tuple),
737 2,
738 "Number of success packets on link 1 should be 2");
739 NS_TEST_ASSERT_MSG_EQ(successMap.at(nodeDeviceTuple),
740 4,
741 "Number of success packets should be 4");
742 NS_TEST_ASSERT_MSG_EQ(totalSuccesses, 4, "Number of success packets should be 4");
743
744 NS_TEST_ASSERT_MSG_EQ(retransmissionMap.at(nodeDeviceTuple),
745 2,
746 "Number of retransmitted successful packets should be 2");
747 NS_TEST_ASSERT_MSG_EQ(totalRetransmissions,
748 2,
749 "Number of retransmitted successful packets (aggregate) should be 2");
750 NS_TEST_ASSERT_MSG_EQ(failureMap.at(nodeDeviceTuple),
751 2,
752 "Number of failed packets should be 2");
753 NS_TEST_ASSERT_MSG_EQ(totalFailures, 2, "Number of failed packets (aggregate) should be 2");
754 NS_TEST_ASSERT_MSG_EQ(totalFailuresQos,
755 2,
756 "Number of dropped packets (aggregate) by QosTxop should be 2");
757 NS_TEST_ASSERT_MSG_EQ(totalFailuresQosMap.at(nodeDeviceTuple),
758 2,
759 "Number of dropped packets (aggregate) by QosTxop should be 2");
760
761 auto successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
763 successRecordLink0It->m_nodeId,
764 1,
765 "Source node ID of the 1st successful data packet on link 0 should be 1");
766 std::advance(successRecordLink0It, 1);
768 successRecordLink0It->m_nodeId,
769 1,
770 "Source node ID of the 2nd successful data packet on link 0 should be 1");
771 auto successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
773 successRecordLink1It->m_nodeId,
774 1,
775 "Source node ID of the 1st successful data packet on link 0 should be 1");
776 std::advance(successRecordLink1It, 1);
778 successRecordLink1It->m_nodeId,
779 1,
780 "Source node ID of the 2nd successful data packet on link 0 should be 1");
781 auto failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
782 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_nodeId,
783 1,
784 "Source node ID of the failed data packet on link 0 should be 1");
785 std::advance(failureRecordIt, 1);
786 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_nodeId,
787 1,
788 "Source node ID of the failed data packet on link 1 should be 1");
789
790 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
791 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_deviceId,
792 0,
793 "Device ID of the 1st successful data packet on link 0 should be 0");
794 std::advance(successRecordLink0It, 1);
795 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_deviceId,
796 0,
797 "Device ID of the 2nd successful data packet on link 0 should be 0");
798 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
799 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_deviceId,
800 0,
801 "Device ID of the 1st successful data packet on link 0 should be 0");
802 std::advance(successRecordLink1It, 1);
803 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_deviceId,
804 0,
805 "Device ID of the 2nd successful data packet on link 1 should be 0");
806 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
807 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_deviceId,
808 0,
809 "Device ID of the failed data packet on link 1 should be 0");
810 std::advance(failureRecordIt, 1);
811 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_deviceId,
812 0,
813 "Device ID of the failed data packet on link 1 should be 0");
814
815 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
817 *successRecordLink0It->m_successLinkIdSet.begin(),
818 0,
819 "Successful link ID of the 1st successful data packet on link 0 should be 0");
820 std::advance(successRecordLink0It, 1);
822 *successRecordLink0It->m_successLinkIdSet.begin(),
823 0,
824 "Successful link ID of the 2nd successful data packet on link 0 should be 0");
825 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
827 *successRecordLink1It->m_successLinkIdSet.begin(),
828 1,
829 "Successful link ID of the 1st successful data packet on link 1 should be 1");
830 std::advance(successRecordLink1It, 1);
832 *successRecordLink1It->m_successLinkIdSet.begin(),
833 1,
834 "Successful link ID of the 2nd successful data packet on link 1 should be 1");
835 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
837 failureRecordIt->m_successLinkIdSet.empty(),
838 true,
839 "Successful link ID set of the failed data packet on link 0 should be empty");
840 std::advance(failureRecordIt, 1);
842 failureRecordIt->m_successLinkIdSet.empty(),
843 true,
844 "Successful link ID set of the failed data packet on link 1 should be empty");
845
846 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
848 successRecordLink0It->m_retransmissions,
849 0,
850 "The 1st successful data packet on link 0 should have no retransmissions");
851 std::advance(successRecordLink0It, 1);
853 successRecordLink0It->m_retransmissions,
854 1,
855 "The 2nd successful data packet on link 0 should have 1 retransmission");
856 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
858 successRecordLink1It->m_retransmissions,
859 0,
860 "The 1st successful data packet on link 1 should have no retransmissions");
861 std::advance(successRecordLink1It, 1);
863 successRecordLink1It->m_retransmissions,
864 1,
865 "The 2nd successful data packet on link 1 should have 1 retransmission");
866 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
867 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_retransmissions,
868 8,
869 "The failed data packet on link 0 should have 8 retransmissions");
870 std::advance(failureRecordIt, 1);
871 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_retransmissions,
872 8,
873 "The failed data packet on link 1 should have 8 retransmissions");
874
875 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
876 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_tid,
877 3,
878 "The 1st successful data packet on link 0 should have a TID of 3");
879 std::advance(successRecordLink0It, 1);
880 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_tid,
881 3,
882 "The 2nd successful data packet on link 0 should have a TID of 3");
883 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
884 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_tid,
885 4,
886 "The 1st successful data packet on link 1 should have a TID of 4");
887 std::advance(successRecordLink1It, 1);
888 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_tid,
889 4,
890 "The 2nd successful data packet on link 1 should have a TID of 4");
891 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
892 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_tid,
893 3,
894 "The failed data packet on link 0 should have a TID of 3");
895 std::advance(failureRecordIt, 1);
896 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_tid,
897 4,
898 "The failed data packet on link 1 should have a TID of 4");
899
900 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
902 successRecordLink0It->m_mpduSeqNum,
903 0,
904 "The 1st successful data packet on link 0 should have a Seq Num of 0");
905 std::advance(successRecordLink0It, 1);
907 successRecordLink0It->m_mpduSeqNum,
908 1,
909 "The 2nd successful data packet on link 0 should have a Seq Num of 1");
910 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
912 successRecordLink1It->m_mpduSeqNum,
913 0,
914 "The 1st successful data packet on link 1 should have a Seq Num of 0");
915 std::advance(successRecordLink1It, 1);
917 successRecordLink1It->m_mpduSeqNum,
918 2,
919 "The 2nd successful data packet on link 1 should have a Seq Num of 2");
920 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
921 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_mpduSeqNum,
922 2,
923 "The failed data packet on link 0 should have a Seq Num of 2");
924 std::advance(failureRecordIt, 1);
925 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_mpduSeqNum,
926 1,
927 "The failed data packet on link 1 should have a Seq Num of 1");
928
929 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
930 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_txStartTime.IsStrictlyPositive(),
931 true,
932 "The 1st successful data packet on link 0 should have been TXed");
933 std::advance(successRecordLink0It, 1);
934 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_txStartTime.IsStrictlyPositive(),
935 true,
936 "The 2nd successful data packet on link 0 should have been TXed");
937 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
938 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_txStartTime.IsStrictlyPositive(),
939 true,
940 "The 1st successful data packet on link 1 should have been TXed");
941 std::advance(successRecordLink1It, 1);
942 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_txStartTime.IsStrictlyPositive(),
943 true,
944 "The 2nd successful data packet on link 1 should have been TXed");
945 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
946 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_txStartTime.IsStrictlyPositive(),
947 true,
948 "The failed data packet on link 0 should have been TXed");
949 std::advance(failureRecordIt, 1);
950 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_txStartTime.IsStrictlyPositive(),
951 true,
952 "The failed data packet on link 1 should have been TXed");
953
954 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
955 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_ackTime.IsStrictlyPositive(),
956 true,
957 "The 1st successful data packet on link 0 should have been acked");
958 std::advance(successRecordLink0It, 1);
959 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_ackTime.IsStrictlyPositive(),
960 true,
961 "The 2nd successful data packet on link 0 should have been acked");
962 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
963 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_ackTime.IsStrictlyPositive(),
964 true,
965 "The 1st successful data packet on link 1 should have been acked");
966 std::advance(successRecordLink1It, 1);
967 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_ackTime.IsStrictlyPositive(),
968 true,
969 "The 2nd successful data packet on link 1 should have been acked");
970 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
971 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_ackTime.IsStrictlyPositive(),
972 false,
973 "The failed data packet on link 0 should not have been acked");
974 std::advance(failureRecordIt, 1);
975 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_ackTime.IsStrictlyPositive(),
976 false,
977 "The failed data packet on link 1 should not have been acked");
978
979 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
980 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_ackTime.IsStrictlyPositive(),
981 true,
982 "The 1st successful data packet on link 0 should have been dequeued");
983 std::advance(successRecordLink0It, 1);
984 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_ackTime.IsStrictlyPositive(),
985 true,
986 "The 2nd successful data packet on link 0 should have been dequeued");
987 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
988 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_ackTime.IsStrictlyPositive(),
989 true,
990 "The 1st successful data packet on link 1 should have been dequeued");
991 std::advance(successRecordLink1It, 1);
992 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_ackTime.IsStrictlyPositive(),
993 true,
994 "The 2nd successful data packet on link 1 should have been dequeued");
995 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
996 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.has_value() &&
997 failureRecordIt->m_dropReason.has_value(),
998 true,
999 "Missing drop time or reason");
1000 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.value().IsStrictlyPositive(),
1001 true,
1002 "The failed data packet on link 0 should have been dequeued");
1003 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropReason.value(),
1005 "Wrong drop reason");
1006 std::advance(failureRecordIt, 1);
1007 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.has_value() &&
1008 failureRecordIt->m_dropReason.has_value(),
1009 true,
1010 "Missing drop time or reason");
1011 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.value().IsStrictlyPositive(),
1012 true,
1013 "The failed data packet on link 1 should have been dequeued");
1014 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropReason.value(),
1016 "Wrong drop reason");
1017
1018 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
1019 auto successRecordLink0ItNext = successRecordLink0It;
1020 std::advance(successRecordLink0ItNext, 1);
1021 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
1022 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_enqueueTime,
1023 successRecordLink0ItNext->m_enqueueTime,
1024 "Packets on link 0 should be enqueued at the same time");
1025 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_enqueueTime,
1026 failureRecordIt->m_enqueueTime,
1027 "Packets on link 0 should be enqueued at the same time");
1028 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
1029 auto successRecordLink1ItNext = successRecordLink1It;
1030 std::advance(successRecordLink1ItNext, 1);
1031 std::advance(failureRecordIt, 1);
1032 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_enqueueTime,
1033 successRecordLink1ItNext->m_enqueueTime,
1034 "Packets on link 1 should be enqueued at the same time");
1035 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_enqueueTime,
1036 failureRecordIt->m_enqueueTime,
1037 "Packets on link 1 should be enqueued at the same time");
1038
1039 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
1040 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink0It->m_txStartTime,
1041 successRecordLink0It->m_enqueueTime,
1042 "The 1st data packet on link 0 should be TXed after enqueued");
1043 std::advance(successRecordLink0It, 1);
1044 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink0It->m_txStartTime,
1045 successRecordLink0It->m_enqueueTime,
1046 "The 2nd data packet on link 0 should be TXed after enqueued");
1047 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
1048 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink1It->m_txStartTime,
1049 successRecordLink1It->m_enqueueTime,
1050 "The 1st data packet on link 1 should be TXed after enqueued");
1051 std::advance(successRecordLink1It, 1);
1052 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink1It->m_txStartTime,
1053 successRecordLink1It->m_enqueueTime,
1054 "The 2nd data packet on link 1 should be TXed after enqueued");
1055 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
1056 NS_TEST_ASSERT_MSG_GT_OR_EQ(failureRecordIt->m_txStartTime,
1057 failureRecordIt->m_enqueueTime,
1058 "The 3rd data packet on link 0 should be TXed after enqueued");
1059 std::advance(failureRecordIt, 1);
1060 NS_TEST_ASSERT_MSG_GT_OR_EQ(failureRecordIt->m_txStartTime,
1061 failureRecordIt->m_enqueueTime,
1062 "The 3rd data packet on link 1 should be TXed after enqueued");
1063
1064 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
1065 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink0It->m_txStartTime,
1066 m_txStartTimes[0][11] + m_durations[0][11] + m_aifss[0],
1067 "link 0 pkt first tx should be after the 11th packet on link");
1068 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink0It->m_txStartTime,
1069 m_txStartTimes[0][11] + m_durations[0][11] + m_aifss[0] +
1070 tolerance + m_cwMins[0] * m_slot,
1071 "link 0 pkt first backoff should not exceed cwMin");
1072 successRecordLink0ItNext = successRecordLink0It;
1073 std::advance(successRecordLink0ItNext, 1);
1074 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
1075 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_txStartTime,
1076 successRecordLink0ItNext->m_txStartTime,
1077 "3 pkts of link 0 should tx at the same time");
1078 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_txStartTime,
1079 failureRecordIt->m_txStartTime,
1080 "3 pkts of link 0 should tx at the same time");
1081
1082 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
1083 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink1It->m_txStartTime,
1084 m_txStartTimes[1][10] + m_durations[1][10] + m_aifss[1],
1085 "link 1 pkt first tx should be after the 10th packet on link");
1086 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink1It->m_txStartTime,
1087 m_txStartTimes[1][10] + m_durations[1][10] + m_aifss[1] +
1088 tolerance + m_cwMins[1] * m_slot,
1089 "link 1 pkt first backoff should not exceed cwMin");
1090 successRecordLink1ItNext = successRecordLink1It;
1091 std::advance(successRecordLink1ItNext, 1);
1092 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
1093 std::advance(failureRecordIt, 1);
1094 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_txStartTime,
1095 successRecordLink1ItNext->m_txStartTime,
1096 "3 pkts of link 1 should tx at the same time");
1097 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_txStartTime,
1098 failureRecordIt->m_txStartTime,
1099 "3 pkts of link 1 should tx at the same time");
1100
1101 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
1102 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink0It->m_ackTime,
1103 m_txStartTimes[0][12] + m_durations[0][12] + m_sifs +
1104 m_durations[0][13],
1105 "Wrong first Block Ack reception time on link 0");
1106 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink0It->m_ackTime,
1107 m_txStartTimes[0][12] + m_durations[0][12] + m_sifs +
1108 m_durations[0][13] + 2 * tolerance,
1109 "Wrong first Block Ack reception time on link 0");
1110 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
1111 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink1It->m_ackTime,
1112 m_txStartTimes[1][11] + m_durations[1][11] + m_sifs +
1113 m_durations[1][12],
1114 "Wrong first Block Ack reception time on link 1");
1115 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink1It->m_ackTime,
1116 m_txStartTimes[1][11] + m_durations[1][11] + m_sifs +
1117 m_durations[1][12] + 2 * tolerance,
1118 "Wrong first Block Ack reception time on link 1");
1119
1120 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
1121 std::advance(successRecordLink0It, 1);
1122 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink0It->m_ackTime,
1123 m_txStartTimes[0][14] + m_durations[0][14] + m_sifs +
1124 m_durations[0][15],
1125 "Wrong second Block Ack reception time on link 0");
1126 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink0It->m_ackTime,
1127 m_txStartTimes[0][14] + m_durations[0][14] + m_sifs +
1128 m_durations[0][15] + 2 * tolerance,
1129 "Wrong second Block Ack reception time on link 0");
1130 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
1131 std::advance(successRecordLink1It, 1);
1132 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink1It->m_ackTime,
1133 m_txStartTimes[1][13] + m_durations[1][13] + m_sifs +
1134 m_durations[1][14],
1135 "Wrong second Block Ack reception time on link 1");
1136 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink1It->m_ackTime,
1137 m_txStartTimes[1][13] + m_durations[1][13] + m_sifs +
1138 m_durations[1][14] + 2 * tolerance,
1139 "Wrong second Block Ack reception time on link 1");
1140 }
1141}
1142
1143/**
1144 * @ingroup wifi-test
1145 * @ingroup tests
1146 *
1147 * @brief WifiTxStatsHelper Test Suite
1148 */
1150{
1151 public:
1153};
1154
1156 : TestSuite("wifi-tx-stats-helper", Type::UNIT)
1157{
1158 // A test case to evaluate the transmission process of multiple Wi-Fi MAC Layer MPDUs in
1159 // a single link device. This testcase uses .11a to test the handling of regular ACKs.
1160 //
1161 // This class tests the WifiTxStatsHelper output by creating three transmission cases:
1162 // 1) packet is sent successfully on the first try
1163 // 2) packet is lost on the first try but successfully transmitted on the second try
1164 // 3) packet is lost on all seven tries and a failure is logged
1165 // The MPDU losses are forced by the use of WifiPhy post-reception error model.
1166 //
1167 // This test also connects to the PHY trace PhyTxPsduBegin and records the sequence of
1168 // transmission times and packet durations observed at the PHY layer, to cross-check against
1169 // the times recorded in the WifiTxStatsHelper record (traced at the MAC layer).
1170 // The testcase also checks the various fields in this helper's output records for correctness.
1171 // AddTestCase(new WifiTxStatsHelperTest("Check single link non-QoS configuration",
1172 // WifiTxStatsHelperTest::SINGLE_LINK_NON_QOS),
1173 // TestCase::Duration::QUICK);
1174
1175 // A test case to evaluate the transmission process of multiple Wi-Fi MAC Layer MPDUs in
1176 // a multi link device. This testcase, unlike the previous, uses .11be to test the
1177 // handling of MPDU aggregation, Block ACKs, and Multi-Link Operation.
1178 //
1179 // This class tests the WifiTxStatsHelper output by creating three transmission cases:
1180 // 1) packet is sent successfully on the first try
1181 // 2) packet is lost on the first try (in an A-MPDU) but successfully transmitted on the
1182 // second try (also in an A-MPDU)
1183 // 3) packet is lost on all 9 tries (first 2 in A-MPDU, other 7 alone) and a failure is logged
1184 // The MPDU losses are forced by the use of WifiPhy post-reception error model.
1185 //
1186 // This test also connects to the PHY trace PhyTxPsduBegin and records the sequence of
1187 // transmission times and packet durations observed at the PHY layer, to cross-check against
1188 // the times recorded in the WifiTxStatsHelper record (traced at the MAC layer).
1189 // The testcase also checks the various fields in this helper's output records for correctness.
1190 AddTestCase(new WifiTxStatsHelperTest("Check multi-link QoS configuration",
1193}
1194
Implements a test case to evaluate the transmission process of multiple Wi-Fi MAC Layer MPDUs.
void DoRun() override
Implementation to actually run this TestCase.
void CheckResults(const WifiTxStatsHelper &wifiTxStats)
Check correctness of test.
int64_t m_streamNumber
Random variable stream number.
NodeContainer m_wifiStaNodes
NodeContainer for STAs.
std::map< uint8_t, Time > m_aifss
Map of AIFSs, indexed per link (for MULTI_LINK_QOS case only)
std::map< uint8_t, std::vector< Time > > m_durations
Map of vector of MPDU durations, indexed per link.
std::map< uint8_t, std::vector< Time > > m_txStartTimes
Map of independently obtain vector of PhyTxBegin trace, indexed per link.
WifiTxStatsHelperTest(const std::string &testName, TestOption option)
Constructor.
std::map< uint8_t, uint32_t > m_cwMins
Map of CW Mins, indexed per link.
std::map< uint8_t, uint32_t > m_aifsns
Map of AIFSNs, indexed per link (for MULTI_LINK_QOS case only)
NodeContainer m_wifiApNode
NodeContainer for AP.
Time m_difs
DIFS time (for SINGLE_LINK_NON_QOS case only)
void Transmit(std::string context, WifiConstPsduMap psduMap, WifiTxVector txVector, Watt_u txPower)
Callback invoked when PHY starts transmission of a PSDU, used to record TX start time and TX duration...
TestOption m_option
Test option.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
WifiTxStatsHelper Test Suite.
AttributeValue implementation for Boolean.
Definition boolean.h:26
Helper class used to assign positions and mobility models to nodes.
holds a vector of ns3::NetDevice pointers
Iterator Begin() const
Get an iterator which refers to the first NetDevice in the container.
void Add(NetDeviceContainer other)
Append the contents of another NetDeviceContainer to the end of this container.
Iterator End() const
Get an iterator which indicates past-the-last NetDevice in the container.
keep track of a set of node pointers.
an address for a packet socket
void SetPhysicalAddress(const Address address)
Set the destination address.
void SetSingleDevice(uint32_t device)
Set the address to match only a specified NetDevice.
Give ns3::PacketSocket powers to ns3::Node.
void Install(Ptr< Node > node) const
Aggregate an instance of a ns3::PacketSocketFactory onto the provided node.
static void SetRun(uint64_t run)
Set the run number of simulation.
static void SetSeed(uint32_t seed)
Set the seed.
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static void Run()
Run the simulation.
Definition simulator.cc:167
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:175
Make it easy to create and manage PHY objects for the spectrum model.
The IEEE 802.11 SSID Information Element.
Definition ssid.h:25
AttributeValue implementation for Ssid.
Definition ssid.h:85
Hold variables of type string.
Definition string.h:45
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
@ QUICK
Fast test.
Definition test.h:1055
TestCase(const TestCase &)=delete
Type
Type of test.
Definition test.h:1274
TestSuite(std::string name, Type type=Type::UNIT)
Construct a new test suite.
Definition test.cc:490
static constexpr auto UNIT
Definition test.h:1291
Simulation virtual time values and global simulation resolution.
Definition nstime.h:96
@ US
microsecond
Definition nstime.h:109
AttributeValue implementation for Time.
Definition nstime.h:1456
Hold an unsigned integer type.
Definition uinteger.h:34
helps to create WifiNetDevice objects
static int64_t AssignStreams(NetDeviceContainer c, int64_t stream)
Assign a fixed random variable stream number to the random variables used by the PHY and MAC aspects ...
create MAC layers for a ns3::WifiNetDevice.
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1564
Statistics helper for tracking outcomes of data MPDU transmissions.
CountPerNodeDeviceLink_t GetSuccessesByNodeDeviceLink(WifiTxStatsHelper::MultiLinkSuccessType type=FIRST_LINK_IN_SET) const
Return the counts of successful MPDU transmissions in a hash map.
void Stop(Time stopTime)
Set the stop time for statistics collection.
uint64_t GetFailures() const
Return the count of failed MPDU transmissions across all enabled devices.
CountPerNodeDevice_t GetFailuresByNodeDevice() const
Return the counts of failed MPDU transmissions in a hash map.
const MpduRecordsPerNodeDeviceLink_t GetSuccessRecords(WifiTxStatsHelper::MultiLinkSuccessType type=FIRST_LINK_IN_SET) const
Return a hash map of successful MPDU records.
const MpduRecordsPerNodeDevice_t & GetFailureRecords() const
Return a hash map of MPDU records for failed transmissions.
CountPerNodeDevice_t GetSuccessesByNodeDevice() const
Return the counts of successful MPDU transmissions in a hash map.
uint64_t GetSuccesses() const
Return the count of successful MPDU transmissions across all enabled devices.
void Enable(const NodeContainer &nodes)
Enables trace collection for all nodes and WifiNetDevices in the specified NodeContainer.
CountPerNodeDevice_t GetRetransmissionsByNodeDevice() const
Return the counts of MPDU retransmissions in a hash map.
uint64_t GetRetransmissions() const
Return the count of MPDU retransmissions across all enabled devices.
void Start(Time startTime)
Set the start time for statistics collection.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
void SetDefault(std::string name, const AttributeValue &value)
Definition config.cc:886
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition test.h:134
#define NS_TEST_ASSERT_MSG_LT_OR_EQ(actual, limit, msg)
Test that an actual value is less than or equal to a limit and report and abort if not.
Definition test.h:740
#define NS_TEST_ASSERT_MSG_GT_OR_EQ(actual, limit, msg)
Test that an actual value is greater than or equal to a limit and report and abort if not.
Definition test.h:905
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1393
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1405
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1369
@ WIFI_STANDARD_80211a
@ WIFI_STANDARD_80211be
@ WIFI_MAC_DROP_QOS_OLD_PACKET
Definition wifi-mac.h:75
@ WIFI_MAC_DROP_REACHED_RETRY_LIMIT
Definition wifi-mac.h:74
@ WIFI_PHY_BAND_6GHZ
The 6 GHz band.
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
constexpr FrequencyRange WIFI_SPECTRUM_6_GHZ
Identifier for the frequency range covering the wifi spectrum in the 6 GHz band.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:585
static constexpr uint8_t SINGLE_LINK_OP_ID
Link ID for single link operations (helps tracking places where correct link ID is to be used to supp...
Definition wifi-utils.h:280
constexpr FrequencyRange WIFI_SPECTRUM_5_GHZ
Identifier for the frequency range covering the wifi spectrum in the 5 GHz band.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Definition wifi-ppdu.h:38
double Watt_u
Watt weak type.
Definition wifi-units.h:25
static WifiTxStatsHelperTestSuite g_wifiTxStatsHelperTestSuite
the test suite