Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added test for broker side offline messages. #732

Merged
merged 3 commits into from
Nov 22, 2020
Merged

Conversation

redboltz
Copy link
Owner

No description provided.

@redboltz
Copy link
Owner Author

Now, CI is running but I got Segmentation Fault on my local environment.

Here is the log:

test/broker_offline_message --log_level=all
Running 1 test case...
Entering test module "mqtt_client_cpp_test"
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(13): Entering test suite "test_broker_offline_message"
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(17): Entering test case "offline_pubsub_v3_1_1"
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(93): info: check chk("c1_h_connack") has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(94): info: check sp == false has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(95): info: check connack_return_code == mqtt::connect_return_code::accepted has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(106): info: check chk("c2_h_connack1") has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(107): info: check sp == false has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(108): info: check connack_return_code == mqtt::connect_return_code::accepted has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(118): info: check ret has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(125): info: check chk("c2_h_suback") has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(126): info: check results.size() == 1U has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(127): info: check results[0] == mqtt::suback_return_code::success_maximum_qos_2 has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(138): info: check chk("c2_h_close1") has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(149): info: check ret has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(156): info: check chk("c1_h_puback") has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(163): info: check chk("c1_h_pubrec") has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(170): info: check chk("c1_h_pubcomp") has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(113): info: check chk("c2_h_connack2") has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(114): info: check sp == true has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(115): info: check connack_return_code == mqtt::connect_return_code::accepted has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(118): info: check ret has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(184): info: check chk("c2_h_publish1") has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(185): info: check pubopts.get_dup() == mqtt::dup::no has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(186): info: check pubopts.get_qos() == mqtt::qos::at_most_once has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(187): info: check pubopts.get_retain() == mqtt::retain::no has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(188): info: check !packet_id has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(189): info: check topic == "topic1" has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(190): info: check contents == "topic1_contents1" has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(215): info: check ret has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(194): info: check chk("c2_h_publish2") has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(195): info: check pubopts.get_dup() == mqtt::dup::no has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(196): info: check pubopts.get_qos() == mqtt::qos::at_least_once has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(197): info: check pubopts.get_retain() == mqtt::retain::no has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(198): info: check packet_id has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(199): info: check topic == "topic1" has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(200): info: check contents == "topic1_contents2" has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(215): info: check ret has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(204): info: check chk("c2_h_publish3") has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(205): info: check pubopts.get_dup() == mqtt::dup::no has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(206): info: check pubopts.get_qos() == mqtt::qos::exactly_once has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(207): info: check pubopts.get_retain() == mqtt::retain::no has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(208): info: check packet_id has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(209): info: check topic == "topic1" has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(210): info: check contents == "topic1_contents3" has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(215): info: check ret has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(222): info: check chk("c1_h_close") has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(145): info: check chk("c2_h_close2") has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(149): info: check ret has passed
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(244): info: check chk.all() has passed
unknown location(0): fatal error: in "test_broker_offline_message/offline_pubsub_v3_1_1": memory access violation at address: 0x559736a87b88: no mapping at fault address
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(244): last checkpoint
Test is aborted
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(17): Leaving test case "offline_pubsub_v3_1_1"; testing time: 4272us
Test is aborted
/home/kondo/work/mqtt_cpp/test/broker_offline_message.cpp(13): Leaving test suite "test_broker_offline_message"
Test is aborted
Leaving test module "mqtt_client_cpp_test"

*** 1 failure is detected in the test module "mqtt_client_cpp_test"

And here is backtrace (from bottom to top)

It seems that the access violation happened at subscription_map.hpp

/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/hashtable.h

1560          // Find the node whose key compares equal to k in the bucket bkt.                                                                                                          │1561          // Return nullptr if no node is found.                                                                                                                                     │1562          template<typename _Key, typename _Value,                                                                                                                                   │
│   1563                   typename _Alloc, typename _ExtractKey, typename _Equal,                                                                                                           │
│   1564                   typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,                                                                                               │
│   1565                   typename _Traits>                                                                                                                                                 │
│   1566            auto                                                                                                                                                                     │
│   1567            _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,                                                                                                                    │
│   1568                       _H1, _H2, _Hash, _RehashPolicy, _Traits>::                                                                                                                    │
│   1569            _M_find_before_node(size_type __bkt, const key_type& __k,                                                                                                                │
│   1570                                __hash_code __code) const                                                                                                                            │
│   1571            -> __node_base*                                                                                                                                                          │
│   1572            {                                                                                                                                                                        │
│   1573              __node_base* __prev_p = _M_buckets[__bkt];                                                                                                                             │
│   1574              if (!__prev_p)                                                                                                                                                         │
│   1575                return nullptr;                                                                                                                                                      │
│   1576                                                                                                                                                                                     │
│  >1577              for (__node_type* __p = static_cast<__node_type*>(__prev_p->_M_nxt);;     

/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/hashtable.h

689               __node_type*                                                                                                                                                           │
│   690               _M_find_node(size_type __bkt, const key_type& __key,                                                                                                                   │
│   691                            __hash_code __c) const                                                                                                                                    │
│   692               {                                                                                                                                                                      │
│  >693                 __node_base* __before_n = _M_find_before_node(__bkt, __key, __c);  

/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/hashtable.h

1442          template<typename _Key, typename _Value,                                                                                                                                   │
│   1443                   typename _Alloc, typename _ExtractKey, typename _Equal,                                                                                                           │
│   1444                   typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,                                                                                               │
│   1445                   typename _Traits>                                                                                                                                                 │
│   1446            auto                                                                                                                                                                     │
│   1447            _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,                                                                                                                    │
│   1448                       _H1, _H2, _Hash, _RehashPolicy, _Traits>::                                                                                                                    │
│   1449            find(const key_type& __k)                                                                                                                                                │
│   1450            -> iterator                                                                                                                                                              │
│   1451            {                                                                                                                                                                        │
│   1452              __hash_code __code = this->_M_hash_code(__k);                                                                                                                          │
│   1453              std::size_t __bkt = _M_bucket_index(__k, __code);                                                                                                                      │
│  >1454              __node_type* __p = _M_find_node(__bkt, __k, __code);    

/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/unordered_map.h

918               iterator                                                                                                                                                               │
│   919               find(const key_type& __x)                                                                                                                                              │
│  >920               { return _M_h.find(__x); }  

/home/kondo/work/mqtt_cpp/test/subscription_map.hpp

│  >181             map_type_iterator get_key(path_entry_key key) { return map.find(key); }    

/home/kondo/work/mqtt_cpp/test/subscription_map.hpp

608             // Remove a value at the specified handle                                                                                                                                │609             // returns the number of removed elements                                                                                                                                │610             std::size_t erase(handle const &h, Key const& key) {                                                                                                                     │
│   611                 // Find the handle in the map                                                                                                                                        │
│  >612                 auto h_iter = this->get_key(h);     

/home/kondo/work/mqtt_cpp/test/test_broker.hpp

1779                void unsubscribe_all() {                                                                                                                                             │
│   1780                    for (auto const& h : handles) {                                                                                                                                  │
│  >1781                        subs_map_.value().get().erase(h, client_id);      

/home/kondo/work/mqtt_cpp/test/test_broker.hpp

1771                void clean() {                                                                                                                                                       │
│   1772                    topic_alias_recv = MQTT_NS::nullopt;                                                                                                                             │
│   1773                    inflight_messages.clear();                                                                                                                                       │
│   1774                    offline_messages.clear();                                                                                                                                        │
│   1775                    qos2_publish_processed.clear();                                                                                                                                  │
│  >1776                    unsubscribe_all();       

/home/kondo/work/mqtt_cpp/test/test_broker.hpp

1733                ~session_state() {                                                                                                                                                   │
│  >1734                    clean(); 

@redboltz
Copy link
Owner Author

I've fixed it by myself. It was member variable order (lifetime) problem.
I will add v5 test.

@kleunen
Copy link
Contributor

kleunen commented Nov 22, 2020

I've fixed it by myself. It was member variable order (lifetime) problem.
I will add v5 test.

order of destruction was not correct ? subs_map destroyed first, sessions destroyed and trying to unregister from non-existing subs_map ?

@redboltz
Copy link
Owner Author

I've fixed it by myself. It was member variable order (lifetime) problem.
I will add v5 test.

order of destruction was not correct ?

Yes. subs_map_ is destructed earlier than sessions_ on test_broker destruction.

@kleunen
Copy link
Contributor

kleunen commented Nov 22, 2020

I've fixed it by myself. It was member variable order (lifetime) problem.
I will add v5 test.

order of destruction was not correct ?

Yes. subs_map_ is destructed earlier than sessions_ on test_broker destruction.

ah yes,

did we not have a discussion before about reference_wrapper vs shared_ptr ? :)

or is totally unrelated ? ;)

@codecov
Copy link

codecov bot commented Nov 22, 2020

Codecov Report

Merging #732 (dc2effc) into master (c07d419) will not change coverage.
The diff coverage is n/a.

@@           Coverage Diff           @@
##           master     #732   +/-   ##
=======================================
  Coverage   84.68%   84.68%           
=======================================
  Files          47       47           
  Lines        7026     7026           
=======================================
  Hits         5950     5950           
  Misses       1076     1076           

@redboltz
Copy link
Owner Author

Now, v5 tests are added. When CI passed, I will merge the PR.
Then could you rebase your PR from the master?

ah yes,
did we not have a discussion before about reference_wrapper vs shared_ptr ? :)
or is totally unrelated ? ;)

It difficult to describe but memory violation is better than hiding the design problem using shared_ptr abuse for me.
I fixed the issue using one hour. The cost to keep a good design (clear ownership) is very small for me.

You might have a different design policy. But for mqtt_cpp, please respect my policy.

@redboltz
Copy link
Owner Author

All CI tests passed.
merged.

@redboltz redboltz merged commit bb31379 into master Nov 22, 2020
@redboltz redboltz deleted the broker_offline_message branch November 22, 2020 13:29
@kleunen
Copy link
Contributor

kleunen commented Nov 22, 2020

You might have a different design policy. But for mqtt_cpp, please respect my policy

No problem. But i would add comment that you are dependent on order of destruction of two data structures. Or possibly enforce the order somehow.

@redboltz
Copy link
Owner Author

You might have a different design policy. But for mqtt_cpp, please respect my policy

No problem. But i would add comment that you are dependent on order of destruction of two data structures. Or possibly enforce the order somehow.

If I use rust programming language, I guess that enforcing it easily (maybe automatically). But I don't know a good way to do that in C++. One option is compile with address sanitizer. It discover access violation quickly (not perfect). I've already added it on CI.

@redboltz
Copy link
Owner Author

redboltz commented Nov 22, 2020

It is off topic.
I sometimes consider that translating my project to rust.
The biggest missing piece of rust library is multi_index (for me).
See https://stackoverflow.com/questions/62110567/boostmulti-index-like-container-in-rust

I tried writing multi_index by rust but it is extremely difficult for me. So I gave up it ;)

@kleunen
Copy link
Contributor

kleunen commented Nov 22, 2020

I find it interesting to understand why you would choose this pattern and learn from your approach. Maybe I have more theoretical approach than practical :)

If you use rust, you really have consider ownership and references much more. Because the borrow checker disallows many common C++ pattern, many are considered not valid. Even though they are practical and are valid in practice.

Not sure how many people will use your library if you use Rust, I think it has more value now in C++ :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants