From 0c6202245d2f013d071d0664637385c8e8d8735b Mon Sep 17 00:00:00 2001 From: Balazs Racz Date: Tue, 20 Aug 2024 23:22:44 +0200 Subject: [PATCH] Adds a test verifying that reserved but not used aliases do not generate an AMR frame upon conflict. --- src/openlcb/IfCan.cxxtest | 103 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/src/openlcb/IfCan.cxxtest b/src/openlcb/IfCan.cxxtest index cdf30caf4..53cebfdb4 100644 --- a/src/openlcb/IfCan.cxxtest +++ b/src/openlcb/IfCan.cxxtest @@ -2,6 +2,7 @@ #include "openlcb/CanDefs.hxx" #include "openlcb/WriteHelper.hxx" +#include "os/FakeClock.hxx" namespace openlcb { @@ -141,6 +142,108 @@ TEST_F(AsyncIfTest, AMEReceiveSupport) wait(); } +void print_alias_cache_entry(void *, NodeID id, NodeAlias alias) +{ + LOG(INFO, " alias %03x: 0x%012" PRIx64, alias, id); +} + +void print_alias_cache(AliasCache *ac, const char *s) +{ + LOG(INFO, "%salias cache:", s); + ac->for_each(&print_alias_cache_entry, nullptr); +} + +TEST_F(AsyncIfTest, NewNodeWithAliasConflict) +{ + FakeClock clk; + AliasCache *ac; + run_x([this, &ac]() { ac = ifCan_->local_aliases(); }); + print_alias_cache(ac, "local "); + + print_all_packets(); + + expect_next_alias_allocation(0xB84); + // This is what simplestack does to get aliases. + run_x([this]() { + ifCan_->alias_allocator()->send(ifCan_->alias_allocator()->alloc()); + }); + wait(); + clk.advance(MSEC_TO_NSEC(250)); + wait(); + clk.advance(MSEC_TO_NSEC(250)); + wait(); + print_alias_cache(ac, "local "); + expect_packet(":X10701B84N0501010114DD;"); + expect_packet(":X19100B84N0501010114DD;"); + DefaultNode nn {ifCan_.get(), 0x0501010114dd}; + wait(); + + print_alias_cache(ac, "local "); + + expect_next_alias_allocation(0xDE1); + // Another alias, this will be reserved. + run_x([this]() { + ifCan_->alias_allocator()->send(ifCan_->alias_allocator()->alloc()); + }); + wait(); + clk.advance(MSEC_TO_NSEC(250)); + wait(); + print_alias_cache(ac, "local "); + + // Conflict with DE1, which is reserved but not allocated (no node is in + // permitted state with it), will not cause a RID frame to be sent. + clear_expect(true); + EXPECT_EQ(CanDefs::get_reserved_alias_node_id(0xDE1), + ac->lookup(NodeAlias(0xDE1))); + + send_packet(":X19100DE1N030000000001;"); + wait(); + clear_expect(true); + // Kicked out of the cache. + EXPECT_EQ(0u, ac->lookup(NodeAlias(0xDE1))); + print_alias_cache(ac, "local "); + + // Starts a new node. This will get a new alias, not the one that + // conflicted. + expect_next_alias_allocation(0x03E); + DefaultNode nnn {ifCan_.get(), 0x0501010114ee}; + wait(); + expect_packet(":X1070103EN0501010114EE;"); + expect_packet(":X1910003EN0501010114EE;"); + clk.advance(MSEC_TO_NSEC(250)); + wait(); + clear_expect(true); + EXPECT_EQ(nnn.node_id(), ac->lookup(NodeAlias(0x03E))); + + print_alias_cache(ac, "local "); + + // Conflict with B84, which is allocated to nn and in permitted state, will + // make an RID frame sent. + EXPECT_EQ(nn.node_id(), ac->lookup(NodeAlias(0xB84))); + expect_packet(":X10703B84N0501010114DD;"); + send_packet(":X19100B84N030000000002;"); + wait(); + clear_expect(true); + // Confirms that the conflicted alias is not in the map. + EXPECT_EQ(0u, ac->lookup(NodeAlias(0xB84))); + EXPECT_EQ(0u, ac->lookup(nn.node_id())); + + print_alias_cache(ac, "local "); + + // Next message out from nn will do a new alias allocation. + expect_next_alias_allocation(0x29B); + send_event(&nn, 0x0102030405060708u); + wait(); + expect_packet(":X1070129BN0501010114DD;"); + expect_packet(":X195B429BN0102030405060708;"); + clk.advance(MSEC_TO_NSEC(250)); + wait(); + clear_expect(true); + + EXPECT_EQ(nn.node_id(), ac->lookup(NodeAlias(0x29B))); + EXPECT_EQ(0x29Bu, ac->lookup(nn.node_id())); +} + TEST_F(AsyncIfTest, GetDefaultNodeId) { EXPECT_EQ(TEST_NODE_ID, ifCan_->get_default_node_id());