| // Copyright 2023 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef QUICHE_QUIC_MOQT_TOOLS_MOQT_MOCK_VISITOR_H_ |
| #define QUICHE_QUIC_MOQT_TOOLS_MOQT_MOCK_VISITOR_H_ |
| |
| #include <cstdint> |
| #include <memory> |
| #include <optional> |
| #include <utility> |
| #include <variant> |
| #include <vector> |
| |
| #include "absl/status/status.h" |
| #include "absl/status/statusor.h" |
| #include "absl/strings/string_view.h" |
| #include "quiche/quic/core/quic_time.h" |
| #include "quiche/quic/moqt/moqt_messages.h" |
| #include "quiche/quic/moqt/moqt_priority.h" |
| #include "quiche/quic/moqt/moqt_publisher.h" |
| #include "quiche/quic/moqt/moqt_session.h" |
| #include "quiche/quic/moqt/moqt_track.h" |
| #include "quiche/common/platform/api/quiche_test.h" |
| |
| namespace moqt::test { |
| |
| struct MockSessionCallbacks { |
| testing::MockFunction<void()> session_established_callback; |
| testing::MockFunction<void(absl::string_view)> goaway_received_callback; |
| testing::MockFunction<void(absl::string_view)> session_terminated_callback; |
| testing::MockFunction<void()> session_deleted_callback; |
| testing::MockFunction<std::optional<MoqtAnnounceErrorReason>( |
| const TrackNamespace&, std::optional<VersionSpecificParameters>)> |
| incoming_announce_callback; |
| testing::MockFunction<std::optional<MoqtSubscribeErrorReason>( |
| TrackNamespace, std::optional<VersionSpecificParameters>)> |
| incoming_subscribe_announces_callback; |
| |
| MockSessionCallbacks() { |
| ON_CALL(incoming_announce_callback, Call(testing::_, testing::_)) |
| .WillByDefault(DefaultIncomingAnnounceCallback); |
| ON_CALL(incoming_subscribe_announces_callback, Call(testing::_, testing::_)) |
| .WillByDefault(DefaultIncomingSubscribeAnnouncesCallback); |
| } |
| |
| MoqtSessionCallbacks AsSessionCallbacks() { |
| return MoqtSessionCallbacks{ |
| session_established_callback.AsStdFunction(), |
| goaway_received_callback.AsStdFunction(), |
| session_terminated_callback.AsStdFunction(), |
| session_deleted_callback.AsStdFunction(), |
| incoming_announce_callback.AsStdFunction(), |
| incoming_subscribe_announces_callback.AsStdFunction()}; |
| } |
| }; |
| |
| class MockTrackPublisher : public MoqtTrackPublisher { |
| public: |
| explicit MockTrackPublisher(FullTrackName name) |
| : track_name_(std::move(name)) { |
| ON_CALL(*this, GetDeliveryOrder()) |
| .WillByDefault(testing::Return(MoqtDeliveryOrder::kAscending)); |
| } |
| const FullTrackName& GetTrackName() const override { return track_name_; } |
| |
| MOCK_METHOD(std::optional<PublishedObject>, GetCachedObject, |
| (Location sequence), (const, override)); |
| MOCK_METHOD(std::vector<Location>, GetCachedObjectsInRange, |
| (Location start, Location end), (const, override)); |
| MOCK_METHOD(void, AddObjectListener, (MoqtObjectListener * listener), |
| (override)); |
| MOCK_METHOD(void, RemoveObjectListener, (MoqtObjectListener * listener), |
| (override)); |
| MOCK_METHOD(absl::StatusOr<MoqtTrackStatusCode>, GetTrackStatus, (), |
| (const, override)); |
| MOCK_METHOD(Location, GetLargestLocation, (), (const, override)); |
| MOCK_METHOD(MoqtForwardingPreference, GetForwardingPreference, (), |
| (const, override)); |
| MOCK_METHOD(MoqtPriority, GetPublisherPriority, (), (const, override)); |
| MOCK_METHOD(MoqtDeliveryOrder, GetDeliveryOrder, (), (const, override)); |
| MOCK_METHOD(std::unique_ptr<MoqtFetchTask>, Fetch, |
| (Location, uint64_t, std::optional<uint64_t>, MoqtDeliveryOrder), |
| (override)); |
| |
| private: |
| FullTrackName track_name_; |
| }; |
| |
| class MockSubscribeRemoteTrackVisitor : public SubscribeRemoteTrack::Visitor { |
| public: |
| MOCK_METHOD(void, OnReply, |
| (const FullTrackName& full_track_name, |
| std::optional<Location> largest_id, |
| std::optional<absl::string_view> error_reason_phrase), |
| (override)); |
| MOCK_METHOD(void, OnCanAckObjects, (MoqtObjectAckFunction ack_function), |
| (override)); |
| MOCK_METHOD(void, OnObjectFragment, |
| (const FullTrackName& full_track_name, Location sequence, |
| MoqtPriority publisher_priority, MoqtObjectStatus status, |
| absl::string_view object, bool end_of_message), |
| (override)); |
| MOCK_METHOD(void, OnSubscribeDone, (FullTrackName full_track_name), |
| (override)); |
| }; |
| |
| class MockPublishingMonitorInterface : public MoqtPublishingMonitorInterface { |
| public: |
| MOCK_METHOD(void, OnObjectAckSupportKnown, (bool supported), (override)); |
| MOCK_METHOD(void, OnObjectAckReceived, |
| (uint64_t group_id, uint64_t object_id, |
| quic::QuicTimeDelta delta_from_deadline), |
| (override)); |
| }; |
| |
| class MockFetchTask : public MoqtFetchTask { |
| public: |
| MockFetchTask() {}; // No synchronous callbacks. |
| MockFetchTask(std::optional<MoqtFetchOk> fetch_ok, |
| std::optional<MoqtFetchError> fetch_error, |
| bool synchronous_object_available) |
| : synchronous_fetch_ok_(fetch_ok), |
| synchronous_fetch_error_(fetch_error), |
| synchronous_object_available_(synchronous_object_available) { |
| QUICHE_DCHECK(!synchronous_fetch_ok_.has_value() || |
| !synchronous_fetch_error_.has_value()); |
| } |
| |
| MOCK_METHOD(MoqtFetchTask::GetNextObjectResult, GetNextObject, |
| (PublishedObject & output), (override)); |
| MOCK_METHOD(absl::Status, GetStatus, (), (override)); |
| |
| void SetObjectAvailableCallback(ObjectsAvailableCallback callback) override { |
| objects_available_callback_ = std::move(callback); |
| if (synchronous_object_available_) { |
| // The first call is installed by the session to trigger stream creation. |
| // An object might not exist yet. |
| objects_available_callback_(); |
| } |
| // The second call is a result of the stream replacing the callback, which |
| // means there is an object available. |
| synchronous_object_available_ = true; |
| } |
| void SetFetchResponseCallback(FetchResponseCallback callback) override { |
| if (synchronous_fetch_ok_.has_value()) { |
| std::move(callback)(*synchronous_fetch_ok_); |
| return; |
| } |
| if (synchronous_fetch_error_.has_value()) { |
| std::move(callback)(*synchronous_fetch_error_); |
| return; |
| } |
| fetch_response_callback_ = std::move(callback); |
| } |
| |
| void CallObjectsAvailableCallback() { objects_available_callback_(); }; |
| void CallFetchResponseCallback( |
| std::variant<MoqtFetchOk, MoqtFetchError> response) { |
| std::move(fetch_response_callback_)(response); |
| } |
| |
| private: |
| FetchResponseCallback fetch_response_callback_; |
| ObjectsAvailableCallback objects_available_callback_; |
| std::optional<MoqtFetchOk> synchronous_fetch_ok_; |
| std::optional<MoqtFetchError> synchronous_fetch_error_; |
| bool synchronous_object_available_ = false; |
| }; |
| |
| } // namespace moqt::test |
| |
| #endif // QUICHE_QUIC_MOQT_TOOLS_MOQT_MOCK_VISITOR_H_ |