blob: ed24f01f0c44761ab678383f16d5c9f3d7dca679 [file] [log] [blame]
// Copyright 2014 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 "base/bind.h"
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "content/child/child_process.h"
#include "content/renderer/media/video_capture_impl.h"
#include "content/renderer/media/video_capture_impl_manager.h"
#include "content/renderer/media/video_capture_message_filter.h"
#include "media/base/bind_to_current_loop.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using ::testing::DoAll;
using ::testing::SaveArg;
using media::BindToCurrentLoop;
namespace content {
ACTION_P(RunClosure, closure) {
closure.Run();
}
class MockVideoCaptureImpl : public VideoCaptureImpl {
public:
MockVideoCaptureImpl(media::VideoCaptureSessionId session_id,
VideoCaptureMessageFilter* filter,
base::Closure destruct_callback)
: VideoCaptureImpl(session_id, filter),
destruct_callback_(destruct_callback) {
}
~MockVideoCaptureImpl() override { destruct_callback_.Run(); }
private:
base::Closure destruct_callback_;
DISALLOW_COPY_AND_ASSIGN(MockVideoCaptureImpl);
};
class MockVideoCaptureImplManager : public VideoCaptureImplManager {
public:
explicit MockVideoCaptureImplManager(
base::Closure destruct_video_capture_callback)
: destruct_video_capture_callback_(
destruct_video_capture_callback) {}
~MockVideoCaptureImplManager() override {}
protected:
VideoCaptureImpl* CreateVideoCaptureImplForTesting(
media::VideoCaptureSessionId id,
VideoCaptureMessageFilter* filter) const override {
return new MockVideoCaptureImpl(id,
filter,
destruct_video_capture_callback_);
}
private:
base::Closure destruct_video_capture_callback_;
DISALLOW_COPY_AND_ASSIGN(MockVideoCaptureImplManager);
};
class VideoCaptureImplManagerTest : public ::testing::Test {
public:
VideoCaptureImplManagerTest()
: manager_(new MockVideoCaptureImplManager(
BindToCurrentLoop(cleanup_run_loop_.QuitClosure()))) {
params_.requested_format = media::VideoCaptureFormat(
gfx::Size(176, 144), 30, media::VIDEO_CAPTURE_PIXEL_FORMAT_I420);
child_process_.reset(new ChildProcess());
}
void FakeChannelSetup() {
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
child_process_->io_task_runner();
if (!task_runner->BelongsToCurrentThread()) {
task_runner->PostTask(
FROM_HERE, base::Bind(&VideoCaptureImplManagerTest::FakeChannelSetup,
base::Unretained(this)));
return;
}
manager_->video_capture_message_filter()->OnFilterAdded(NULL);
}
protected:
MOCK_METHOD2(OnFrameReady,
void(const scoped_refptr<media::VideoFrame>&,
base::TimeTicks estimated_capture_time));
MOCK_METHOD0(OnStarted, void());
MOCK_METHOD0(OnStopped, void());
void OnStateUpdate(VideoCaptureState state) {
switch (state) {
case VIDEO_CAPTURE_STATE_STARTED:
OnStarted();
break;
case VIDEO_CAPTURE_STATE_STOPPED:
OnStopped();
break;
default:
NOTREACHED();
}
}
base::Closure StartCapture(const media::VideoCaptureSessionId id,
const media::VideoCaptureParams& params) {
return manager_->StartCapture(
id, params, base::Bind(&VideoCaptureImplManagerTest::OnStateUpdate,
base::Unretained(this)),
base::Bind(&VideoCaptureImplManagerTest::OnFrameReady,
base::Unretained(this)));
}
base::MessageLoop message_loop_;
scoped_ptr<ChildProcess> child_process_;
media::VideoCaptureParams params_;
base::RunLoop cleanup_run_loop_;
scoped_ptr<MockVideoCaptureImplManager> manager_;
private:
DISALLOW_COPY_AND_ASSIGN(VideoCaptureImplManagerTest);
};
TEST_F(VideoCaptureImplManagerTest, MultipleImpls) {
base::Closure release_cb1 = manager_->UseDevice(0);
base::Closure release_cb2 = manager_->UseDevice(1);
base::Closure stop_cb1, stop_cb2;
{
base::RunLoop run_loop;
base::Closure quit_closure = BindToCurrentLoop(run_loop.QuitClosure());
EXPECT_CALL(*this, OnStarted()).WillOnce(RunClosure(quit_closure));
EXPECT_CALL(*this, OnStarted()).RetiresOnSaturation();
stop_cb1 = StartCapture(0, params_);
stop_cb2 = StartCapture(1, params_);
FakeChannelSetup();
run_loop.Run();
}
{
base::RunLoop run_loop;
base::Closure quit_closure = BindToCurrentLoop(run_loop.QuitClosure());
EXPECT_CALL(*this, OnStopped()).WillOnce(RunClosure(quit_closure));
EXPECT_CALL(*this, OnStopped()).RetiresOnSaturation();
stop_cb1.Run();
stop_cb2.Run();
run_loop.Run();
}
release_cb1.Run();
release_cb2.Run();
cleanup_run_loop_.Run();
}
TEST_F(VideoCaptureImplManagerTest, RefusesMultipleClients) {
// TODO(ajose): EXPECT_DEATH is unsafe in a threaded context - what to use
// instead?
base::Closure release_cb1 = manager_->UseDevice(0);
// Use DCHECK_IS_ON rather than EXPECT_DEBUG_DEATH or similar to avoid
// issues on release builds that include DCHECKs.
#if DCHECK_IS_ON()
EXPECT_DEATH(manager_->UseDevice(0), "");
#endif
}
TEST_F(VideoCaptureImplManagerTest, NoLeak) {
manager_->UseDevice(0).Reset();
manager_.reset();
cleanup_run_loop_.Run();
}
} // namespace content