зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1004530 - Part 3: Unit test that verifies that new pairs will start when local gather happens after all preceding pairs have failed, provided the grace period has not elapsed. Also a couple more tests that use a new test-case feature.
This commit is contained in:
Родитель
48f7bf25bd
Коммит
7def3b061f
|
@ -59,6 +59,9 @@ const uint16_t kDefaultStunServerPort=3478;
|
|||
const std::string kBogusIceCandidate(
|
||||
(char *)"candidate:0 2 UDP 2113601790 192.168.178.20 50769 typ");
|
||||
|
||||
const std::string kUnreachableHostIceCandidate(
|
||||
(char *)"candidate:0 1 UDP 2113601790 192.168.178.20 50769 typ host");
|
||||
|
||||
std::string g_stun_server_address(kDefaultStunServerAddress);
|
||||
std::string g_stun_server_hostname(kDefaultStunServerHostname);
|
||||
std::string g_turn_server;
|
||||
|
@ -85,7 +88,7 @@ static std::string SabotageHostCandidateAndDropReflexive(
|
|||
}
|
||||
|
||||
if (candidate.find("typ host") != std::string::npos) {
|
||||
return kBogusIceCandidate;
|
||||
return kUnreachableHostIceCandidate;
|
||||
}
|
||||
|
||||
return candidate;
|
||||
|
@ -138,6 +141,74 @@ class IceCandidatePairCompare {
|
|||
}
|
||||
};
|
||||
|
||||
class IceTestPeer;
|
||||
|
||||
class SchedulableTrickleCandidate {
|
||||
public:
|
||||
SchedulableTrickleCandidate(IceTestPeer *peer,
|
||||
size_t stream,
|
||||
const std::string &candidate) :
|
||||
peer_(peer),
|
||||
stream_(stream),
|
||||
candidate_(candidate),
|
||||
timer_handle_(nullptr) {
|
||||
}
|
||||
|
||||
~SchedulableTrickleCandidate() {
|
||||
if (timer_handle_)
|
||||
NR_async_timer_cancel(timer_handle_);
|
||||
}
|
||||
|
||||
void Schedule(unsigned int ms) {
|
||||
test_utils->sts_target()->Dispatch(
|
||||
WrapRunnable(this, &SchedulableTrickleCandidate::Schedule_s, ms),
|
||||
NS_DISPATCH_SYNC);
|
||||
}
|
||||
|
||||
void Schedule_s(unsigned int ms) {
|
||||
MOZ_ASSERT(!timer_handle_);
|
||||
NR_ASYNC_TIMER_SET(ms, Trickle_cb, this, &timer_handle_);
|
||||
}
|
||||
|
||||
static void Trickle_cb(NR_SOCKET s, int how, void *cb_arg) {
|
||||
static_cast<SchedulableTrickleCandidate*>(cb_arg)->Trickle();
|
||||
}
|
||||
|
||||
void Trickle();
|
||||
|
||||
std::string& Candidate() {
|
||||
return candidate_;
|
||||
}
|
||||
|
||||
const std::string& Candidate() const {
|
||||
return candidate_;
|
||||
}
|
||||
|
||||
size_t Stream() const {
|
||||
return stream_;
|
||||
}
|
||||
|
||||
bool IsHost() const {
|
||||
return candidate_.find("typ host") != std::string::npos;
|
||||
}
|
||||
|
||||
bool IsReflexive() const {
|
||||
return candidate_.find("typ srflx") != std::string::npos;
|
||||
}
|
||||
|
||||
bool IsRelay() const {
|
||||
return candidate_.find("typ relay") != std::string::npos;
|
||||
}
|
||||
|
||||
private:
|
||||
IceTestPeer *peer_;
|
||||
size_t stream_;
|
||||
std::string candidate_;
|
||||
void *timer_handle_;
|
||||
|
||||
DISALLOW_COPY_ASSIGN(SchedulableTrickleCandidate);
|
||||
};
|
||||
|
||||
class IceTestPeer : public sigslot::has_slots<> {
|
||||
public:
|
||||
|
||||
|
@ -364,23 +435,37 @@ class IceTestPeer : public sigslot::has_slots<> {
|
|||
void SimulateTrickle(size_t stream) {
|
||||
std::cerr << "Doing trickle for stream " << stream << std::endl;
|
||||
// If we are in trickle deferred mode, now trickle in the candidates
|
||||
// for |stream}
|
||||
nsresult res;
|
||||
// for |stream|
|
||||
|
||||
ASSERT_GT(remote_->streams_.size(), stream);
|
||||
|
||||
std::vector<SchedulableTrickleCandidate*>& candidates =
|
||||
ControlTrickle(stream);
|
||||
|
||||
for (auto i = candidates.begin(); i != candidates.end(); ++i) {
|
||||
(*i)->Schedule(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Allows test case to completely control when/if candidates are trickled
|
||||
// (test could also do things like insert extra trickle candidates, or
|
||||
// change existing ones, or insert duplicates, really anything is fair game)
|
||||
std::vector<SchedulableTrickleCandidate*>& ControlTrickle(size_t stream) {
|
||||
std::cerr << "Doing controlled trickle for stream " << stream << std::endl;
|
||||
|
||||
std::vector<std::string> candidates =
|
||||
remote_->GetCandidates(stream);
|
||||
|
||||
for (size_t j=0; j<candidates.size(); j++) {
|
||||
test_utils->sts_target()->Dispatch(
|
||||
WrapRunnableRet(streams_[stream],
|
||||
&NrIceMediaStream::ParseTrickleCandidate,
|
||||
candidates[j],
|
||||
&res), NS_DISPATCH_SYNC);
|
||||
|
||||
ASSERT_TRUE(NS_SUCCEEDED(res));
|
||||
controlled_trickle_candidates_[stream].push_back(
|
||||
new SchedulableTrickleCandidate(this, stream, candidates[j]));
|
||||
}
|
||||
|
||||
return controlled_trickle_candidates_[stream];
|
||||
}
|
||||
|
||||
nsresult TrickleCandidate_s(const std::string &candidate, size_t stream) {
|
||||
return streams_[stream]->ParseTrickleCandidate(candidate);
|
||||
}
|
||||
|
||||
void DumpCandidate(std::string which, const NrIceCandidate& cand) {
|
||||
|
@ -457,6 +542,14 @@ class IceTestPeer : public sigslot::has_slots<> {
|
|||
}
|
||||
|
||||
void Shutdown() {
|
||||
for (auto s = controlled_trickle_candidates_.begin();
|
||||
s != controlled_trickle_candidates_.end();
|
||||
++s) {
|
||||
for (auto cand = s->second.begin(); cand != s->second.end(); ++cand) {
|
||||
delete *cand;
|
||||
}
|
||||
}
|
||||
|
||||
ice_ctx_ = nullptr;
|
||||
}
|
||||
|
||||
|
@ -702,6 +795,9 @@ class IceTestPeer : public sigslot::has_slots<> {
|
|||
nsRefPtr<NrIceCtx> ice_ctx_;
|
||||
std::vector<mozilla::RefPtr<NrIceMediaStream> > streams_;
|
||||
std::map<std::string, std::vector<std::string> > candidates_;
|
||||
// Maps from stream id to list of remote trickle candidates
|
||||
std::map<size_t, std::vector<SchedulableTrickleCandidate*> >
|
||||
controlled_trickle_candidates_;
|
||||
bool gathering_complete_;
|
||||
int ready_ct_;
|
||||
bool ice_complete_;
|
||||
|
@ -718,6 +814,12 @@ class IceTestPeer : public sigslot::has_slots<> {
|
|||
int trickled_;
|
||||
};
|
||||
|
||||
void SchedulableTrickleCandidate::Trickle() {
|
||||
timer_handle_ = nullptr;
|
||||
nsresult res = peer_->TrickleCandidate_s(candidate_, stream_);
|
||||
ASSERT_TRUE(NS_SUCCEEDED(res));
|
||||
}
|
||||
|
||||
class IceGatherTest : public ::testing::Test {
|
||||
public:
|
||||
void SetUp() {
|
||||
|
@ -1274,6 +1376,82 @@ TEST_F(IceConnectTest, TestConnectTurnWithDelay) {
|
|||
WaitForComplete();
|
||||
}
|
||||
|
||||
void RealisticTrickleDelay(
|
||||
std::vector<SchedulableTrickleCandidate*>& candidates) {
|
||||
for (size_t i = 0; i < candidates.size(); ++i) {
|
||||
SchedulableTrickleCandidate* cand = candidates[i];
|
||||
if (cand->IsHost()) {
|
||||
cand->Schedule(i*10);
|
||||
} else if (cand->IsReflexive()) {
|
||||
cand->Schedule(i*10 + 100);
|
||||
} else if (cand->IsRelay()) {
|
||||
cand->Schedule(i*10 + 200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DelayRelayCandidates(
|
||||
std::vector<SchedulableTrickleCandidate*>& candidates,
|
||||
unsigned int ms) {
|
||||
for (auto i = candidates.begin(); i != candidates.end(); ++i) {
|
||||
if ((*i)->IsRelay()) {
|
||||
(*i)->Schedule(ms);
|
||||
} else {
|
||||
(*i)->Schedule(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(IceConnectTest, TestConnectTurnWithNormalTrickleDelay) {
|
||||
if (g_turn_server.empty())
|
||||
return;
|
||||
|
||||
AddStream("first", 1);
|
||||
SetTurnServer(g_turn_server, kDefaultStunServerPort,
|
||||
g_turn_user, g_turn_password);
|
||||
ASSERT_TRUE(Gather(true));
|
||||
ConnectTrickle();
|
||||
RealisticTrickleDelay(p1_->ControlTrickle(0));
|
||||
RealisticTrickleDelay(p2_->ControlTrickle(0));
|
||||
|
||||
ASSERT_TRUE_WAIT(p1_->ice_complete(), 5000);
|
||||
ASSERT_TRUE_WAIT(p2_->ice_complete(), 5000);
|
||||
}
|
||||
|
||||
TEST_F(IceConnectTest, TestConnectTurnWithNormalTrickleDelayOneSided) {
|
||||
if (g_turn_server.empty())
|
||||
return;
|
||||
|
||||
AddStream("first", 1);
|
||||
SetTurnServer(g_turn_server, kDefaultStunServerPort,
|
||||
g_turn_user, g_turn_password);
|
||||
ASSERT_TRUE(Gather(true));
|
||||
ConnectTrickle();
|
||||
RealisticTrickleDelay(p1_->ControlTrickle(0));
|
||||
p2_->SimulateTrickle(0);
|
||||
|
||||
ASSERT_TRUE_WAIT(p1_->ice_complete(), 5000);
|
||||
ASSERT_TRUE_WAIT(p2_->ice_complete(), 5000);
|
||||
}
|
||||
|
||||
TEST_F(IceConnectTest, TestConnectTurnWithLargeTrickleDelay) {
|
||||
if (g_turn_server.empty())
|
||||
return;
|
||||
|
||||
AddStream("first", 1);
|
||||
SetTurnServer(g_turn_server, kDefaultStunServerPort,
|
||||
g_turn_user, g_turn_password);
|
||||
SetCandidateFilter(SabotageHostCandidateAndDropReflexive);
|
||||
ASSERT_TRUE(Gather(true));
|
||||
ConnectTrickle();
|
||||
// Trickle host candidates immediately, but delay relay candidates
|
||||
DelayRelayCandidates(p1_->ControlTrickle(0), 3700);
|
||||
DelayRelayCandidates(p2_->ControlTrickle(0), 3700);
|
||||
|
||||
ASSERT_TRUE_WAIT(p1_->ice_complete(), 5000);
|
||||
ASSERT_TRUE_WAIT(p2_->ice_complete(), 5000);
|
||||
}
|
||||
|
||||
TEST_F(IceConnectTest, TestConnectTurnTcp) {
|
||||
if (g_turn_server.empty())
|
||||
return;
|
||||
|
|
Загрузка…
Ссылка в новой задаче