1 /* Copyright 2016, Ableton AG, Berlin. All rights reserved. 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 2 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 * 16 * If you would like to incorporate Link into a proprietary software application, 17 * please contact <link-devs@ableton.com>. 18 */ 19 20 #include <ableton/discovery/Payload.hpp> 21 #include <ableton/discovery/test/Socket.hpp> 22 #include <ableton/link/GhostXForm.hpp> 23 #include <ableton/link/NodeState.hpp> 24 #include <ableton/link/PayloadEntries.hpp> 25 #include <ableton/link/PingResponder.hpp> 26 #include <ableton/link/SessionId.hpp> 27 #include <ableton/link/v1/Messages.hpp> 28 #include <ableton/platforms/asio/AsioWrapper.hpp> 29 #include <ableton/test/CatchWrapper.hpp> 30 #include <ableton/util/Log.hpp> 31 #include <ableton/util/test/IoService.hpp> 32 #include <array> 33 34 namespace ableton 35 { 36 namespace link 37 { 38 namespace 39 { 40 41 struct RpFixture 42 { 43 RpFixture() 44 : mAddress(asio::ip::address_v4::from_string("127.0.0.1")) 45 , mResponder(mAddress, 46 NodeId::random(), 47 GhostXForm{1.0, std::chrono::microseconds{0}}, 48 util::injectVal(util::test::IoService{}), 49 MockClock{}, 50 util::injectVal(util::NullLog{})) 51 { 52 } 53 54 discovery::test::Socket responderSocket() 55 { 56 return mResponder.socket(); 57 } 58 59 std::size_t numSentMessages() 60 { 61 return responderSocket().sentMessages.size(); 62 } 63 64 struct MockClock 65 { 66 std::chrono::microseconds micros() const 67 { 68 return std::chrono::microseconds{4}; 69 } 70 }; 71 72 asio::ip::address_v4 mAddress = asio::ip::address_v4::from_string("127.0.0.1"); 73 PingResponder<util::test::IoService, MockClock, discovery::test::Socket, util::NullLog> 74 mResponder; 75 }; 76 77 } // anonymous namespace 78 79 TEST_CASE("PingResponder | ReplyToPing", "[PingResponder]") 80 { 81 using std::chrono::microseconds; 82 83 RpFixture fixture; 84 85 // Construct and send Ping Message. Check if Responder sent back a Message 86 const auto payload = 87 discovery::makePayload(HostTime{microseconds(2)}, PrevGHostTime{microseconds(1)}); 88 89 v1::MessageBuffer buffer; 90 const auto msgBegin = std::begin(buffer); 91 const auto msgEnd = v1::pingMessage(payload, msgBegin); 92 const auto endpoint = asio::ip::udp::endpoint(fixture.mAddress, 8888); 93 94 fixture.responderSocket().incomingMessage(endpoint, msgBegin, msgEnd); 95 96 CHECK(1 == fixture.numSentMessages()); 97 98 // Check Responder's message 99 const auto messageBuffer = fixture.responderSocket().sentMessages[0].first; 100 const auto result = v1::parseMessageHeader(begin(messageBuffer), end(messageBuffer)); 101 const auto& hdr = result.first; 102 103 std::chrono::microseconds ghostTime{0}; 104 std::chrono::microseconds prevGHostTime{0}; 105 std::chrono::microseconds hostTime{0}; 106 discovery::parsePayload<GHostTime, PrevGHostTime, HostTime>(result.second, 107 std::end(messageBuffer), 108 [&ghostTime](GHostTime gt) { ghostTime = std::move(gt.time); }, 109 [&prevGHostTime](PrevGHostTime gt) { prevGHostTime = std::move(gt.time); }, 110 [&hostTime](HostTime ht) { hostTime = std::move(ht.time); }); 111 112 CHECK(v1::kPong == hdr.messageType); 113 CHECK(std::chrono::microseconds{2} == hostTime); 114 CHECK(std::chrono::microseconds{1} == prevGHostTime); 115 CHECK(std::chrono::microseconds{4} == ghostTime); 116 } 117 118 TEST_CASE("PingResponder | PingSizeExceeding", "[PingResponder]") 119 { 120 using std::chrono::microseconds; 121 122 RpFixture fixture; 123 124 const auto ht = HostTime{microseconds(2)}; 125 const auto payload = discovery::makePayload(ht, ht, ht); 126 127 v1::MessageBuffer buffer; 128 const auto msgBegin = std::begin(buffer); 129 const auto msgEnd = v1::pingMessage(payload, msgBegin); 130 131 const auto endpoint = asio::ip::udp::endpoint(fixture.mAddress, 8888); 132 133 fixture.responderSocket().incomingMessage(endpoint, msgBegin, msgEnd); 134 135 CHECK(0 == fixture.numSentMessages()); 136 } 137 138 } // namespace link 139 } // namespace ableton 140