* Use the current thread as the signaling thread and worker thread to keep the unit test simple and easier to debug.

* I also merged the issue 113007.

This will be uploaded to the libjingle patch, so you may comment there if you want.

There's failure in the tests now, but I will let you review the threading change at the same time I will try to resolve the failure.
Review URL: http://webrtc-codereview.appspot.com/120002

git-svn-id: http://webrtc.googlecode.com/svn/trunk@426 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
wu@webrtc.org 2011-08-23 20:57:29 +00:00
parent ae53bf87d7
commit 87c9b74b11

View File

@ -27,6 +27,8 @@
#include <stdio.h>
#include <list>
#include "base/gunit.h"
#include "base/helpers.h"
#include "talk/app/webrtc/webrtcsession.h"
@ -263,97 +265,8 @@ class OnSignalImpl
std::vector<cricket::Candidate> last_candidates_;
};
template<typename T>
struct ReturnValue : public talk_base::MessageData {
ReturnValue() : return_value_() {}
T return_value_;
};
typedef ReturnValue<bool> ReturnBool;
typedef ReturnValue<const std::vector<cricket::Candidate>*>
ReturnCandidates;
template <typename T>
class PassArgument : public talk_base::MessageData {
class WebRtcSessionTest : public OnSignalImpl {
public:
explicit PassArgument(const T& argument) : argument_(argument) {}
const T& argument() { return argument_; }
protected:
T argument_;
};
typedef PassArgument<bool> PassBool;
typedef PassArgument<cricket::BaseSession::Error> PassError;
typedef PassArgument<std::pair<cricket::VoiceChannel*, std::string> >
PassVoiceChannelString;
typedef PassArgument<std::pair<cricket::VideoChannel*, std::string> >
PassVideoChannelString;
template <typename T>
class ReturnBoolPassArgument : public talk_base::MessageData {
public:
explicit ReturnBoolPassArgument(const T& argument)
: argument_(argument) { return_value_ = false; }
const T& argument() { return argument_; }
bool return_value_;
protected:
T argument_;
};
typedef ReturnBoolPassArgument<std::pair<std::string, bool> >
ReturnBoolPassStringBool;
typedef ReturnBoolPassArgument<std::string> ReturnBoolPassString;
typedef ReturnBoolPassArgument<bool> ReturnBoolPassBool;
typedef ReturnBoolPassArgument<
std::pair<std::string, cricket::VideoRenderer*> >
ReturnBoolPassStringVideoRenderer;
class WebRtcSessionExtendedForTest : public webrtc::WebRtcSession {
public:
WebRtcSessionExtendedForTest(const std::string& id,
const std::string& direction,
cricket::PortAllocator* allocator,
cricket::ChannelManager* channelmgr,
talk_base::Thread* signaling_thread)
: WebRtcSession(id, direction, allocator, channelmgr, signaling_thread),
worker_thread_(channelmgr->worker_thread()) {
}
private:
virtual cricket::Transport* CreateTransport() {
ASSERT(signaling_thread()->IsCurrent());
return static_cast<cricket::Transport*> (new cricket::FakeTransport(
signaling_thread(),
worker_thread_));
}
talk_base::Thread* worker_thread_;
};
class WebRtcSessionTest : public OnSignalImpl,
public talk_base::MessageHandler {
public:
enum FunctionCallId {
kCallInitiate,
kCallConnect,
kCallOnRemoteDescription,
kCallOnInitiateMessage,
kCallMuted,
kCallCameraMuted,
kCallCreateVoiceChannel,
kCallCreateVideoChannel,
kCallRemoveStream,
kCallRemoveAllStreams,
kCallHasStreamString,
kCallHasStreamBool,
kCallHasAudioStream,
kCallHasVideoStream,
kCallSetVideoRenderer,
kCallLocalCandidates
};
enum {kInit = kCallLocalCandidates + 1};
enum {kTerminate = kInit + 1};
static WebRtcSessionTest* CreateWebRtcSessionTest(bool receiving) {
WebRtcSessionTest* return_value =
new WebRtcSessionTest();
@ -392,45 +305,21 @@ class WebRtcSessionTest : public OnSignalImpl,
bool Init(bool receiving) {
if (signaling_thread_ != NULL)
return false;
signaling_thread_ = new talk_base::Thread();
if (!signaling_thread_->SetName("signaling_thread test", this)) {
return false;
}
if (!signaling_thread_->Start()) {
return false;
}
signaling_thread_ = talk_base::Thread::Current();
receiving_ = receiving;
ReturnBool return_value;
signaling_thread_->Send(this, kInit, &return_value);
return return_value.return_value_;
}
void Init_s(talk_base::Message* message) {
ReturnBool* return_value = reinterpret_cast<ReturnBool*>(message->pdata);
return_value->return_value_ = false;
ASSERT_TRUE(worker_thread_ == NULL);
worker_thread_ = new talk_base::Thread();
if (!worker_thread_->SetName("worker thread test", this))
return;
if (!worker_thread_->Start())
return;
if (worker_thread_!= NULL)
return false;
worker_thread_ = talk_base::Thread::Current();
cricket::FakePortAllocator* fake_port_allocator =
new cricket::FakePortAllocator(worker_thread_, NULL);
fake_port_allocator->set_flags(cricket::PORTALLOCATOR_DISABLE_STUN |
cricket::PORTALLOCATOR_DISABLE_RELAY |
cricket::PORTALLOCATOR_DISABLE_TCP);
allocator_ = static_cast<cricket::PortAllocator*>(fake_port_allocator);
channel_manager_ = new cricket::ChannelManager(worker_thread_);
if (!channel_manager_->Init())
return;
return false;
talk_base::CreateRandomString(8, &id_);
@ -454,311 +343,122 @@ class WebRtcSessionTest : public OnSignalImpl,
static_cast<OnSignalImpl*> (this),
&OnSignalImpl::OnFailedCall);
return_value->return_value_ = true;
return;
return true;
}
void Terminate_s() {
void Terminate() {
delete session_;
session_ = NULL;
delete channel_manager_;
channel_manager_ = NULL;
delete allocator_;
allocator_ = NULL;
}
~WebRtcSessionTest() {
if (signaling_thread_ != NULL) {
signaling_thread_->Send(this, kTerminate, NULL);
signaling_thread_->Stop();
signaling_thread_->Clear(NULL);
delete signaling_thread_;
}
if (worker_thread_ != NULL) {
worker_thread_->Stop();
worker_thread_->Clear(NULL);
delete worker_thread_;
}
Terminate();
}
// All session APIs must be called from the signaling thread.
bool CallInitiate() {
ReturnBool return_value;
signaling_thread_->Send(this, kCallInitiate, &return_value);
return return_value.return_value_;
return session_->Initiate();
}
bool CallConnect() {
ReturnBool return_value;
signaling_thread_->Send(this, kCallConnect, &return_value);
if (!session_->Connect())
return false;
// This callback does not happen with FakeTransport!
if (!WaitForCallback(kOnLocalDescription, 1000)) {
return false;
}
return return_value.return_value_;
return true;
}
bool CallOnRemoteDescription() {
ReturnBool return_value;
signaling_thread_->Send(this, kCallOnRemoteDescription, &return_value);
return return_value.return_value_;
bool CallOnRemoteDescription(cricket::SessionDescription* session_shallow,
std::vector<cricket::Candidate>* candidates_shallow) {
std::vector<cricket::Candidate> candidates;
candidates.insert(candidates.end(), candidates_shallow->begin(),
candidates_shallow->end());
if (candidates.empty()) {
return false;
}
cricket::SessionDescription* description = CopySessionDescription(
session_shallow);
if (description == NULL) {
return false;
}
if (!session_->OnRemoteDescription(description, candidates)) {
delete description;
return false;
}
return true;
}
bool CallOnInitiateMessage() {
ReturnBool return_value;
signaling_thread_->Send(this, kCallOnInitiateMessage, &return_value);
return return_value.return_value_;
cricket::SessionDescription* description = NULL;
std::vector<cricket::Candidate> candidates;
if (!GenerateFakeSession(false, &description, &candidates)) {
return false;
}
if (!session_->OnInitiateMessage(description, candidates)) {
delete description;
return false;
}
return true;
}
bool CallCreateVoiceChannel(const std::string& stream_id) {
ReturnBoolPassString return_value(stream_id);
signaling_thread_->Send(this, kCallCreateVoiceChannel, &return_value);
if (!session_->CreateVoiceChannel(stream_id)) {
return false;
}
if (!WaitForCallback(kOnRtcMediaChannelCreated, 1000)) {
return false;
}
return return_value.return_value_;
return true;
}
bool CallCreateVideoChannel(const std::string& stream_id) {
ReturnBoolPassString return_value(stream_id);
signaling_thread_->Send(this, kCallCreateVideoChannel, &return_value);
return return_value.return_value_;
if (!session_->CreateVideoChannel(stream_id)) {
return false;
}
if (!WaitForCallback(kOnRtcMediaChannelCreated, 1000)) {
return false;
}
return true;
}
bool CallRemoveStream(const std::string& stream_id) {
ReturnBoolPassString return_value(stream_id);
signaling_thread_->Send(this, kCallRemoveStream, &return_value);
return return_value.return_value_;
return session_->RemoveStream(stream_id);
}
void CallRemoveAllStreams() {
signaling_thread_->Send(this, kCallRemoveAllStreams, NULL);
session_->RemoveAllStreams();
}
bool CallHasStream(const std::string& label) {
ReturnBoolPassString return_value(label);
signaling_thread_->Send(this, kCallHasStreamString, &return_value);
return return_value.return_value_;
return session_->HasStream(label);
}
bool CallHasStream(bool video) {
ReturnBoolPassBool return_value(video);
signaling_thread_->Send(this, kCallHasStreamBool, &return_value);
return return_value.return_value_;
return session_->HasStream(video);
}
bool CallHasAudioStream() {
ReturnBool return_value;
signaling_thread_->Send(this, kCallHasAudioStream, &return_value);
return return_value.return_value_;
return session_->HasAudioStream();
}
bool CallHasVideoStream() {
ReturnBool return_value;
signaling_thread_->Send(this, kCallHasVideoStream, &return_value);
return return_value.return_value_;
return session_->HasVideoStream();
}
bool CallSetVideoRenderer(const std::string& stream_id,
cricket::VideoRenderer* renderer) {
ReturnBoolPassStringVideoRenderer return_value(std::make_pair(
stream_id, renderer));
signaling_thread_->Send(this, kCallSetVideoRenderer, &return_value);
return return_value.return_value_;
return session_->SetVideoRenderer(stream_id, renderer);
}
const std::vector<cricket::Candidate>& CallLocalCandidates() {
ReturnCandidates return_value;
signaling_thread_->Send(this, kCallLocalCandidates, &return_value);
EXPECT_TRUE(return_value.return_value_ != NULL);
return *return_value.return_value_;
}
void Initiate_s(talk_base::Message* message) {
ReturnBool* return_value = reinterpret_cast<ReturnBool*>(message->pdata);
if (!session_->Initiate()) {
return_value->return_value_ = false;
return;
}
return_value->return_value_ = true;
}
void Connect_s(talk_base::Message* message) {
ReturnBool* return_value = reinterpret_cast<ReturnBool*>(message->pdata);
return_value->return_value_ = session_->Connect();
}
void OnRemoteDescription_s(talk_base::Message* message) {
ReturnBool* return_value = reinterpret_cast<ReturnBool*>(message->pdata);
return_value->return_value_ = false;
std::vector<cricket::Candidate> candidates;
cricket::SessionDescription* description = GetLocalDescription(&candidates);
if (description == NULL) {
return;
}
if (!session_->OnRemoteDescription(description, candidates)) {
delete description;
return;
}
return_value->return_value_ = true;
}
void OnInitiateMessage_s(talk_base::Message* message) {
cricket::SessionDescription* description = NULL;
std::vector<cricket::Candidate> candidates;
ReturnBool* return_value = reinterpret_cast<ReturnBool*>(message->pdata);
if (!GenerateFakeSession(false, &description, &candidates)) {
return_value->return_value_ = false;
return;
}
if (!session_->OnInitiateMessage(description, candidates)) {
return_value->return_value_ = false;
delete description;
return;
}
return_value->return_value_ = true;
}
void Muted_s(talk_base::Message* message) {
ReturnBool* return_value = reinterpret_cast<ReturnBool*>(message->pdata);
return_value->return_value_ = session_->muted();
}
void CameraMuted_s(talk_base::Message* message) {
ReturnBool* return_value = reinterpret_cast<ReturnBool*>(message->pdata);
return_value->return_value_ = session_->camera_muted();
}
void CreateVoiceChannel_s(talk_base::Message* message) {
ReturnBoolPassString* return_value =
reinterpret_cast<ReturnBoolPassString*>(message->pdata);
return_value->return_value_ = session_->CreateVoiceChannel(
return_value->argument());
}
void CreateVideoChannel_s(talk_base::Message* message) {
ReturnBoolPassString* return_value =
reinterpret_cast<ReturnBoolPassString*>(message->pdata);
return_value->return_value_ = session_->CreateVideoChannel(
return_value->argument());
}
void RemoveStream_s(talk_base::Message* message) {
ReturnBoolPassString* return_value =
reinterpret_cast<ReturnBoolPassString*>(message->pdata);
return_value->return_value_ = session_->RemoveStream(
return_value->argument());
}
void RemoveAllStreams_s(talk_base::Message* message) {
EXPECT_TRUE(message->pdata == NULL);
session_->RemoveAllStreams();
}
void HasStreamString_s(talk_base::Message* message) {
ReturnBoolPassString* return_value =
reinterpret_cast<ReturnBoolPassString*>(message->pdata);
return_value->return_value_ = session_->HasStream(return_value->argument());
}
void HasStreamBool_s(talk_base::Message* message) {
ReturnBoolPassBool* return_value = reinterpret_cast<ReturnBoolPassBool*>(
message->pdata);
return_value->return_value_ = session_->HasStream(return_value->argument());
}
void HasAudioStream_s(talk_base::Message* message) {
ReturnBool* return_value = reinterpret_cast<ReturnBool*>(message->pdata);
return_value->return_value_ = session_->HasAudioStream();
}
void HasVideoStream_s(talk_base::Message* message) {
ReturnBool* return_value = reinterpret_cast<ReturnBool*>(message->pdata);
return_value->return_value_ = session_->HasVideoStream();
}
void SetVideoRenderer_s(talk_base::Message* message) {
ReturnBoolPassStringVideoRenderer* return_value =
reinterpret_cast<ReturnBoolPassStringVideoRenderer*>(message->pdata);
return_value->return_value_ = session_->SetVideoRenderer(
return_value->argument().first, return_value->argument().second);
}
void LocalCandidates_s(talk_base::Message* message) {
ReturnCandidates* return_value =
reinterpret_cast<ReturnCandidates*>(message->pdata);
return_value->return_value_ = &session_->local_candidates();
}
void OnMessage(talk_base::Message* message) {
if ((message->pdata == NULL) &&
(message->message_id != kCallRemoveAllStreams) &&
(message->message_id != kTerminate)) {
ADD_FAILURE();
return;
}
if (!signaling_thread_->IsCurrent()) {
ADD_FAILURE();
return;
}
switch (message->message_id) {
case kCallInitiate:
Initiate_s(message);
return;
case kCallConnect:
Connect_s(message);
return;
case kCallOnRemoteDescription:
OnRemoteDescription_s(message);
return;
case kCallOnInitiateMessage:
OnInitiateMessage_s(message);
return;
case kCallMuted:
Muted_s(message);
return;
case kCallCameraMuted:
CameraMuted_s(message);
return;
case kCallCreateVoiceChannel:
CreateVoiceChannel_s(message);
return;
case kCallCreateVideoChannel:
CreateVideoChannel_s(message);
return;
case kCallRemoveStream:
RemoveStream_s(message);
return;
case kCallRemoveAllStreams:
RemoveAllStreams_s(message);
return;
case kCallHasStreamString:
HasStreamString_s(message);
return;
case kCallHasStreamBool:
HasStreamBool_s(message);
return;
case kCallHasAudioStream:
HasAudioStream_s(message);
return;
case kCallHasVideoStream:
HasVideoStream_s(message);
return;
case kCallSetVideoRenderer:
SetVideoRenderer_s(message);
return;
case kCallLocalCandidates:
LocalCandidates_s(message);
return;
case kInit:
Init_s(message);
return;
case kTerminate:
Terminate_s();
return;
default:
ADD_FAILURE();
return;
}
return session_->local_candidates();
}
private:
@ -809,13 +509,11 @@ TEST(WebRtcSessionTest, InitializationReceiveSanity) {
EXPECT_FALSE(my_session->CallHasStream(kVideo));
EXPECT_FALSE(my_session->CallHasStream(!kVideo));
EXPECT_EQ(OnSignalImpl::kNone,
my_session->PopOldestCallback());
}
// TODO(ronghuawu): Add tests for video calls and incoming calls.
TEST(WebRtcSessionTest, SendCallSetUp) {
TEST(WebRtcSessionTest, AudioSendReceiveCallSetUp) {
const bool kReceiving = false;
talk_base::scoped_ptr<WebRtcSessionTest> my_session;
my_session.reset(WebRtcSessionTest::CreateWebRtcSessionTest(kReceiving));
@ -826,8 +524,37 @@ TEST(WebRtcSessionTest, SendCallSetUp) {
ASSERT_TRUE(my_session->CallCreateVoiceChannel("Audio"));
ASSERT_TRUE(my_session->CallConnect());
ASSERT_TRUE(my_session->CallOnRemoteDescription());
std::vector<cricket::Candidate> candidates;
cricket::SessionDescription* local_session = my_session->GetLocalDescription(
&candidates);
ASSERT_FALSE(candidates.empty());
ASSERT_FALSE(local_session == NULL);
ASSERT_TRUE(my_session->CallOnRemoteDescription(local_session, &candidates));
// All callbacks should be caught by my session. Assert it.
ASSERT_FALSE(CallbackReceived(my_session.get(), 1000));
}
TEST(WebRtcSessionTest, VideoSendCallSetUp) {
const bool kReceiving = false;
talk_base::scoped_ptr<WebRtcSessionTest> my_session;
my_session.reset(WebRtcSessionTest::CreateWebRtcSessionTest(kReceiving));
ASSERT_TRUE(my_session.get() != NULL);
ASSERT_TRUE(my_session->CallInitiate());
ASSERT_TRUE(my_session->CallCreateVideoChannel("Video"));
ASSERT_TRUE(my_session->CallConnect());
std::vector<cricket::Candidate> candidates;
cricket::SessionDescription* local_session = my_session->GetLocalDescription(
&candidates);
ASSERT_FALSE(candidates.empty());
ASSERT_FALSE(local_session == NULL);
ASSERT_TRUE(my_session->CallOnRemoteDescription(local_session, &candidates));
// All callbacks should be caught by my session. Assert it.
ASSERT_FALSE(CallbackReceived(my_session.get(), 1000));
}
// TODO(ronghuawu): Add tests for incoming calls.