|  | /* | 
|  | *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  | #ifndef NET_DCSCTP_SOCKET_MOCK_DCSCTP_SOCKET_CALLBACKS_H_ | 
|  | #define NET_DCSCTP_SOCKET_MOCK_DCSCTP_SOCKET_CALLBACKS_H_ | 
|  |  | 
|  | #include <cstdint> | 
|  | #include <deque> | 
|  | #include <memory> | 
|  | #include <optional> | 
|  | #include <string> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include "absl/strings/string_view.h" | 
|  | #include "api/array_view.h" | 
|  | #include "api/task_queue/task_queue_base.h" | 
|  | #include "api/units/time_delta.h" | 
|  | #include "api/units/timestamp.h" | 
|  | #include "net/dcsctp/public/dcsctp_message.h" | 
|  | #include "net/dcsctp/public/dcsctp_socket.h" | 
|  | #include "net/dcsctp/public/timeout.h" | 
|  | #include "net/dcsctp/public/types.h" | 
|  | #include "net/dcsctp/timer/fake_timeout.h" | 
|  | #include "rtc_base/logging.h" | 
|  | #include "rtc_base/random.h" | 
|  | #include "test/gmock.h" | 
|  |  | 
|  | namespace dcsctp { | 
|  |  | 
|  | namespace internal { | 
|  | // It can be argued if a mocked random number generator should be deterministic | 
|  | // or if it should be have as a "real" random number generator. In this | 
|  | // implementation, each instantiation of `MockDcSctpSocketCallbacks` will have | 
|  | // their `GetRandomInt` return different sequences, but each instantiation will | 
|  | // always generate the same sequence of random numbers. This to make it easier | 
|  | // to compare logs from tests, but still to let e.g. two different sockets (used | 
|  | // in the same test) get different random numbers, so that they don't start e.g. | 
|  | // on the same sequence number. While that isn't an issue in the protocol, it | 
|  | // just makes debugging harder as the two sockets would look exactly the same. | 
|  | // | 
|  | // In a real implementation of `DcSctpSocketCallbacks` the random number | 
|  | // generator backing `GetRandomInt` should be seeded externally and correctly. | 
|  | inline int GetUniqueSeed() { | 
|  | static int seed = 0; | 
|  | return ++seed; | 
|  | } | 
|  | }  // namespace internal | 
|  |  | 
|  | class MockDcSctpSocketCallbacks : public DcSctpSocketCallbacks { | 
|  | public: | 
|  | explicit MockDcSctpSocketCallbacks(absl::string_view name = "") | 
|  | : log_prefix_(name.empty() ? "" : std::string(name) + ": "), | 
|  | random_(internal::GetUniqueSeed()), | 
|  | timeout_manager_([this]() { return now_; }) { | 
|  | ON_CALL(*this, SendPacketWithStatus) | 
|  | .WillByDefault([this](webrtc::ArrayView<const uint8_t> data) { | 
|  | sent_packets_.emplace_back( | 
|  | std::vector<uint8_t>(data.begin(), data.end())); | 
|  | return SendPacketStatus::kSuccess; | 
|  | }); | 
|  | ON_CALL(*this, OnMessageReceived) | 
|  | .WillByDefault([this](DcSctpMessage message) { | 
|  | received_messages_.emplace_back(std::move(message)); | 
|  | }); | 
|  |  | 
|  | ON_CALL(*this, OnError) | 
|  | .WillByDefault([this](ErrorKind error, absl::string_view message) { | 
|  | RTC_LOG(LS_WARNING) | 
|  | << log_prefix_ << "Socket error: " << ToString(error) << "; " | 
|  | << message; | 
|  | }); | 
|  | ON_CALL(*this, OnAborted) | 
|  | .WillByDefault([this](ErrorKind error, absl::string_view message) { | 
|  | RTC_LOG(LS_WARNING) | 
|  | << log_prefix_ << "Socket abort: " << ToString(error) << "; " | 
|  | << message; | 
|  | }); | 
|  | ON_CALL(*this, Now).WillByDefault([this]() { return now_; }); | 
|  | } | 
|  |  | 
|  | MOCK_METHOD(SendPacketStatus, | 
|  | SendPacketWithStatus, | 
|  | (webrtc::ArrayView<const uint8_t> data), | 
|  | (override)); | 
|  |  | 
|  | std::unique_ptr<Timeout> CreateTimeout( | 
|  | webrtc::TaskQueueBase::DelayPrecision /* precision */) override { | 
|  | // The fake timeout manager does not implement |precision|. | 
|  | return timeout_manager_.CreateTimeout(); | 
|  | } | 
|  |  | 
|  | MOCK_METHOD(webrtc::Timestamp, Now, (), (override)); | 
|  | uint32_t GetRandomInt(uint32_t low, uint32_t high) override { | 
|  | return random_.Rand(low, high); | 
|  | } | 
|  |  | 
|  | MOCK_METHOD(void, OnMessageReceived, (DcSctpMessage message), (override)); | 
|  | MOCK_METHOD(void, OnMessageReady, (), (override)); | 
|  | MOCK_METHOD(void, | 
|  | OnError, | 
|  | (ErrorKind error, absl::string_view message), | 
|  | (override)); | 
|  | MOCK_METHOD(void, | 
|  | OnAborted, | 
|  | (ErrorKind error, absl::string_view message), | 
|  | (override)); | 
|  | MOCK_METHOD(void, OnConnected, (), (override)); | 
|  | MOCK_METHOD(void, OnClosed, (), (override)); | 
|  | MOCK_METHOD(void, OnConnectionRestarted, (), (override)); | 
|  | MOCK_METHOD(void, | 
|  | OnStreamsResetFailed, | 
|  | (webrtc::ArrayView<const StreamID> outgoing_streams, | 
|  | absl::string_view reason), | 
|  | (override)); | 
|  | MOCK_METHOD(void, | 
|  | OnStreamsResetPerformed, | 
|  | (webrtc::ArrayView<const StreamID> outgoing_streams), | 
|  | (override)); | 
|  | MOCK_METHOD(void, | 
|  | OnIncomingStreamsReset, | 
|  | (webrtc::ArrayView<const StreamID> incoming_streams), | 
|  | (override)); | 
|  | MOCK_METHOD(void, OnBufferedAmountLow, (StreamID stream_id), (override)); | 
|  | MOCK_METHOD(void, OnTotalBufferedAmountLow, (), (override)); | 
|  | MOCK_METHOD(void, | 
|  | OnLifecycleMessageExpired, | 
|  | (LifecycleId lifecycle_id, bool maybe_delivered), | 
|  | (override)); | 
|  | MOCK_METHOD(void, | 
|  | OnLifecycleMessageFullySent, | 
|  | (LifecycleId lifecycle_id), | 
|  | (override)); | 
|  | MOCK_METHOD(void, | 
|  | OnLifecycleMessageDelivered, | 
|  | (LifecycleId lifecycle_id), | 
|  | (override)); | 
|  | MOCK_METHOD(void, OnLifecycleEnd, (LifecycleId lifecycle_id), (override)); | 
|  |  | 
|  | bool HasPacket() const { return !sent_packets_.empty(); } | 
|  |  | 
|  | std::vector<uint8_t> ConsumeSentPacket() { | 
|  | if (sent_packets_.empty()) { | 
|  | return {}; | 
|  | } | 
|  | std::vector<uint8_t> ret = std::move(sent_packets_.front()); | 
|  | sent_packets_.pop_front(); | 
|  | return ret; | 
|  | } | 
|  | std::optional<DcSctpMessage> ConsumeReceivedMessage() { | 
|  | if (received_messages_.empty()) { | 
|  | return std::nullopt; | 
|  | } | 
|  | DcSctpMessage ret = std::move(received_messages_.front()); | 
|  | received_messages_.pop_front(); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | void AdvanceTime(webrtc::TimeDelta duration) { now_ = now_ + duration; } | 
|  | void SetTime(webrtc::Timestamp now) { now_ = now; } | 
|  |  | 
|  | std::optional<TimeoutID> GetNextExpiredTimeout() { | 
|  | return timeout_manager_.GetNextExpiredTimeout(); | 
|  | } | 
|  |  | 
|  | webrtc::TimeDelta GetTimeToNextTimeout() const { | 
|  | return timeout_manager_.GetTimeToNextTimeout(); | 
|  | } | 
|  |  | 
|  | private: | 
|  | const std::string log_prefix_; | 
|  | webrtc::Timestamp now_ = webrtc::Timestamp::Zero(); | 
|  | webrtc::Random random_; | 
|  | FakeTimeoutManager timeout_manager_; | 
|  | std::deque<std::vector<uint8_t>> sent_packets_; | 
|  | std::deque<DcSctpMessage> received_messages_; | 
|  | }; | 
|  | }  // namespace dcsctp | 
|  |  | 
|  | #endif  // NET_DCSCTP_SOCKET_MOCK_DCSCTP_SOCKET_CALLBACKS_H_ |