diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_sink_test.cc')
-rw-r--r-- | chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_sink_test.cc | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_sink_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_sink_test.cc new file mode 100644 index 00000000000..2eb472de7b4 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_sink_test.cc @@ -0,0 +1,244 @@ +// Copyright 2021 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. + +#include "third_party/blink/renderer/modules/mediastream/video_track_signal_underlying_sink.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/web/web_heap.h" +#include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h" +#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_media_stream_track_signal.h" +#include "third_party/blink/renderer/core/streams/writable_stream.h" +#include "third_party/blink/renderer/core/streams/writable_stream_default_writer.h" +#include "third_party/blink/renderer/modules/mediastream/media_stream_track.h" +#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h" +#include "third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.h" +#include "third_party/blink/renderer/platform/mediastream/media_stream_component.h" +#include "third_party/blink/renderer/platform/mediastream/media_stream_source.h" +#include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h" + +using testing::_; + +namespace blink { + +class VideoTrackSignalUnderlyingSinkTest : public testing::Test { + public: + VideoTrackSignalUnderlyingSinkTest() { + mock_video_source_ = new MockMediaStreamVideoSource(); + media_stream_source_ = MakeGarbageCollected<MediaStreamSource>( + "dummy_source_id", MediaStreamSource::kTypeVideo, "dummy_source_name", + /*remote=*/false); + media_stream_source_->SetPlatformSource( + base::WrapUnique(mock_video_source_)); + web_track_ = MediaStreamVideoTrack::CreateVideoTrack( + mock_video_source_, MediaStreamVideoSource::ConstraintsOnceCallback(), + true); + mock_video_source_->StartMockedSource(); + } + + ~VideoTrackSignalUnderlyingSinkTest() override { + platform_->RunUntilIdle(); + mock_video_source_->StopSource(); + base::RunLoop run_loop; + platform_->GetIOTaskRunner()->PostTask(FROM_HERE, run_loop.QuitClosure()); + run_loop.Run(); + WebHeap::CollectAllGarbageForTesting(); + } + + MediaStreamTrack* CreateTrack(ExecutionContext* context) const { + return MakeGarbageCollected<MediaStreamTrack>(context, web_track_); + } + VideoTrackSignalUnderlyingSink* CreateUnderlyingSink( + MediaStreamTrack* track) { + return MakeGarbageCollected<VideoTrackSignalUnderlyingSink>(track); + } + + ScriptValue CreateSignalChunk(ScriptState* script_state, + const String& signal_name) { + MediaStreamTrackSignal* signal = MediaStreamTrackSignal::Create(); + signal->setSignalType(signal_name); + return ScriptValue(script_state->GetIsolate(), + ToV8(signal, script_state->GetContext()->Global(), + script_state->GetIsolate())); + } + + ScriptValue CreateRequestFrameChunk(ScriptState* script_state) { + return CreateSignalChunk(script_state, "request-frame"); + } + + ScriptValue CreateSetMinFrameRateChunk( + ScriptState* script_state, + const base::Optional<double>& frame_rate = 10.0) { + MediaStreamTrackSignal* signal = MediaStreamTrackSignal::Create(); + signal->setSignalType("set-min-frame-rate"); + if (frame_rate) + signal->setFrameRate(*frame_rate); + return ScriptValue(script_state->GetIsolate(), + ToV8(signal, script_state->GetContext()->Global(), + script_state->GetIsolate())); + } + + protected: + Persistent<MediaStreamSource> media_stream_source_; + WebMediaStreamTrack web_track_; + MockMediaStreamVideoSource* mock_video_source_; + ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform_; +}; + +TEST_F(VideoTrackSignalUnderlyingSinkTest, + WriteRequestFrameToStreamForwardsToVideoSource) { + V8TestingScope v8_scope; + ScriptState* script_state = v8_scope.GetScriptState(); + auto* track = CreateTrack(v8_scope.GetExecutionContext()); + auto* underlying_sink = CreateUnderlyingSink(track); + auto* writable_stream = WritableStream::CreateWithCountQueueingStrategy( + script_state, underlying_sink, 1u); + + NonThrowableExceptionState exception_state; + auto* writer = writable_stream->getWriter(script_state, exception_state); + + auto request_frame_chunk = CreateRequestFrameChunk(script_state); + EXPECT_CALL(*mock_video_source_, OnRequestRefreshFrame()); + ScriptPromiseTester write_tester( + script_state, + writer->write(script_state, request_frame_chunk, exception_state)); + write_tester.WaitUntilSettled(); + + const double frame_rate = 14.8; + auto set_min_frame_rate_chunk = + CreateSetMinFrameRateChunk(script_state, frame_rate); + MediaStreamVideoTrack* video_track = + MediaStreamVideoTrack::From(track->Component()); + EXPECT_FALSE(video_track->min_frame_rate().has_value()); + ScriptPromiseTester write_tester2( + script_state, + writer->write(script_state, set_min_frame_rate_chunk, exception_state)); + write_tester2.WaitUntilSettled(); + EXPECT_TRUE(video_track->min_frame_rate().has_value()); + EXPECT_EQ(video_track->min_frame_rate().value(), frame_rate); + + writer->releaseLock(script_state); + ScriptPromiseTester close_tester( + script_state, writable_stream->close(script_state, exception_state)); + close_tester.WaitUntilSettled(); + + MediaStreamTrack* clone = track->clone(script_state); + track->stopTrack(v8_scope.GetExecutionContext()); + + // Writing to the sink after the track closes should fail, even if the source + // is active. + EXPECT_TRUE(mock_video_source_->IsRunning()); + DummyExceptionStateForTesting dummy_exception_state; + underlying_sink->write(script_state, CreateRequestFrameChunk(script_state), + nullptr, dummy_exception_state); + EXPECT_TRUE(dummy_exception_state.HadException()); + EXPECT_EQ(dummy_exception_state.Code(), + static_cast<ExceptionCode>(DOMExceptionCode::kInvalidStateError)); + + clone->stopTrack(v8_scope.GetExecutionContext()); + EXPECT_FALSE(mock_video_source_->IsRunning()); + // Writing to the sink after the source closes should fail. + dummy_exception_state.ClearException(); + underlying_sink->write(script_state, CreateRequestFrameChunk(script_state), + nullptr, dummy_exception_state); + EXPECT_TRUE(dummy_exception_state.HadException()); + EXPECT_EQ(dummy_exception_state.Code(), + static_cast<ExceptionCode>(DOMExceptionCode::kInvalidStateError)); +} + +TEST_F(VideoTrackSignalUnderlyingSinkTest, WriteInvalidDataFails) { + V8TestingScope v8_scope; + ScriptState* script_state = v8_scope.GetScriptState(); + auto* track = CreateTrack(v8_scope.GetExecutionContext()); + auto* underlying_sink = CreateUnderlyingSink(track); + + MediaStreamVideoTrack* video_track = + MediaStreamVideoTrack::From(track->Component()); + EXPECT_FALSE(video_track->min_frame_rate().has_value()); + + DummyExceptionStateForTesting exception_state; + auto set_min_frame_rate_chunk = + CreateSetMinFrameRateChunk(script_state, base::nullopt); + underlying_sink->write(script_state, set_min_frame_rate_chunk, nullptr, + exception_state); + EXPECT_TRUE(exception_state.HadException()); + EXPECT_FALSE(video_track->min_frame_rate().has_value()); + + exception_state.ClearException(); + EXPECT_FALSE(exception_state.HadException()); + underlying_sink->write(script_state, + CreateSignalChunk(script_state, "invalid-signal"), + nullptr, exception_state); + EXPECT_TRUE(exception_state.HadException()); + + // Writing null fails + exception_state.ClearException(); + EXPECT_FALSE(exception_state.HadException()); + underlying_sink->write(script_state, + ScriptValue::CreateNull(v8_scope.GetIsolate()), + nullptr, exception_state); + EXPECT_TRUE(exception_state.HadException()); + + // Writing an intenger fails + exception_state.ClearException(); + EXPECT_FALSE(exception_state.HadException()); + underlying_sink->write(script_state, ScriptValue::From(script_state, 5), + nullptr, exception_state); + EXPECT_TRUE(exception_state.HadException()); + + track->stopTrack(v8_scope.GetExecutionContext()); +} + +TEST_F(VideoTrackSignalUnderlyingSinkTest, WriteToClosedSinkFails) { + V8TestingScope v8_scope; + ScriptState* script_state = v8_scope.GetScriptState(); + auto* track = CreateTrack(v8_scope.GetExecutionContext()); + auto* underlying_sink = CreateUnderlyingSink(track); + + auto* writable_stream = WritableStream::CreateWithCountQueueingStrategy( + script_state, underlying_sink, 1u); + + NonThrowableExceptionState exception_state; + ScriptPromiseTester abort_tester( + script_state, writable_stream->close(script_state, exception_state)); + abort_tester.WaitUntilSettled(); + + // Writing to the sink after the stream closes should fail. + DummyExceptionStateForTesting dummy_exception_state; + underlying_sink->write(script_state, CreateRequestFrameChunk(script_state), + nullptr, dummy_exception_state); + EXPECT_TRUE(dummy_exception_state.HadException()); + EXPECT_EQ(dummy_exception_state.Code(), + static_cast<ExceptionCode>(DOMExceptionCode::kInvalidStateError)); + + track->stopTrack(v8_scope.GetExecutionContext()); +} + +TEST_F(VideoTrackSignalUnderlyingSinkTest, WriteToAbortedSinkFails) { + V8TestingScope v8_scope; + ScriptState* script_state = v8_scope.GetScriptState(); + auto* track = CreateTrack(v8_scope.GetExecutionContext()); + auto* underlying_sink = CreateUnderlyingSink(track); + + auto* writable_stream = WritableStream::CreateWithCountQueueingStrategy( + script_state, underlying_sink, 1u); + + NonThrowableExceptionState exception_state; + ScriptPromiseTester abort_tester( + script_state, writable_stream->abort(script_state, exception_state)); + abort_tester.WaitUntilSettled(); + + // Writing to the sink after the stream aborts should fail. + DummyExceptionStateForTesting dummy_exception_state; + underlying_sink->write(script_state, CreateRequestFrameChunk(script_state), + nullptr, dummy_exception_state); + EXPECT_TRUE(dummy_exception_state.HadException()); + EXPECT_EQ(dummy_exception_state.Code(), + static_cast<ExceptionCode>(DOMExceptionCode::kInvalidStateError)); + + track->stopTrack(v8_scope.GetExecutionContext()); +} + +} // namespace blink |