webrtc/pc/rtcstatstraversal_unittest.cc
Henrik Boström b619936dee Stats traversal algorithm added.
This is part of the work to add a selector argument to getStats().

Changes:
- TakeReferencedStats() added, which traverses the stats graph and takes
  any stats from the report that are directly or indirectly accessible
  from the starting stats objects in the stats graph. The result is
  returned as a stats report.
- GetStatsReferencedIds(), an efficient helper function for getting
  neighbor stats object IDs.
- RTCStatsReport::Take(), removed the stats object with the given ID and
  returns ownership of it (so that it can be added to another report).

TakeReferencedStats() is tested with a bunch of sample stats graphs.

GetStatsReferencedIds() is tested in the rtcstats_integrationttest.cc,
making sure the expected IDs are returned. The expected IDs are the
values of the stats object members with the "Id" or "Ids" suffix.

Design doc:
https://docs.google.com/document/d/18BywbtXgHCjsbR5nWBedpzqDjAfXrFSTJNiADnzoK0w/edit?usp=sharing

Bug: chromium:680172
Change-Id: I5da9da8250da0cb05adb864015901393a4290776
Reviewed-on: https://webrtc-review.googlesource.com/60869
Commit-Queue: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22381}
2018-03-12 10:54:09 +00:00

208 lines
7.1 KiB
C++

/*
* Copyright 2018 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "pc/rtcstatstraversal.h"
#include <memory>
#include <string>
#include <vector>
#include "api/stats/rtcstats_objects.h"
#include "rtc_base/checks.h"
#include "rtc_base/gunit.h"
// This file contains tests for TakeReferencedStats().
// GetStatsNeighborIds() is tested in rtcstats_integrationtest.cc.
namespace webrtc {
class RTCStatsTraversalTest : public testing::Test {
public:
RTCStatsTraversalTest() {
transport_ = new RTCTransportStats("transport", 0);
candidate_pair_ = new RTCIceCandidatePairStats("candidate-pair", 0);
local_candidate_ = new RTCLocalIceCandidateStats("local-candidate", 0);
remote_candidate_ = new RTCRemoteIceCandidateStats("remote-candidate", 0);
initial_report_ = RTCStatsReport::Create(0);
initial_report_->AddStats(std::unique_ptr<const RTCStats>(transport_));
initial_report_->AddStats(std::unique_ptr<const RTCStats>(candidate_pair_));
initial_report_->AddStats(
std::unique_ptr<const RTCStats>(local_candidate_));
initial_report_->AddStats(
std::unique_ptr<const RTCStats>(remote_candidate_));
result_ = RTCStatsReport::Create(0);
}
void TakeReferencedStats(std::vector<const RTCStats*> start_nodes) {
std::vector<std::string> start_ids;
for (const RTCStats* start_node : start_nodes) {
start_ids.push_back(start_node->id());
}
result_ = webrtc::TakeReferencedStats(initial_report_, start_ids);
}
void EXPECT_VISITED(const RTCStats* stats) {
EXPECT_FALSE(initial_report_->Get(stats->id()))
<< '"' << stats->id()
<< "\" should be visited but it was not removed from initial report.";
EXPECT_TRUE(result_->Get(stats->id()))
<< '"' << stats->id()
<< "\" should be visited but it was not added to the resulting report.";
}
void EXPECT_UNVISITED(const RTCStats* stats) {
EXPECT_TRUE(initial_report_->Get(stats->id()))
<< '"' << stats->id()
<< "\" should not be visited but it was removed from initial report.";
EXPECT_FALSE(result_->Get(stats->id()))
<< '"' << stats->id()
<< "\" should not be visited but it was added to the resulting report.";
}
protected:
rtc::scoped_refptr<RTCStatsReport> initial_report_;
rtc::scoped_refptr<RTCStatsReport> result_;
// Raw pointers to stats owned by the reports.
RTCTransportStats* transport_;
RTCIceCandidatePairStats* candidate_pair_;
RTCIceCandidateStats* local_candidate_;
RTCIceCandidateStats* remote_candidate_;
};
TEST_F(RTCStatsTraversalTest, NoReachableConnections) {
// Everything references transport but transport doesn't reference anything.
//
// candidate-pair
// | | |
// v | v
// local-candidate | remote-candidate
// | | |
// v v v
// start:transport
candidate_pair_->transport_id = "transport";
candidate_pair_->local_candidate_id = "local-candidate";
candidate_pair_->remote_candidate_id = "remote-candidate";
local_candidate_->transport_id = "transport";
remote_candidate_->transport_id = "transport";
TakeReferencedStats({transport_});
EXPECT_VISITED(transport_);
EXPECT_UNVISITED(candidate_pair_);
EXPECT_UNVISITED(local_candidate_);
EXPECT_UNVISITED(remote_candidate_);
}
TEST_F(RTCStatsTraversalTest, SelfReference) {
transport_->rtcp_transport_stats_id = "transport";
TakeReferencedStats({transport_});
EXPECT_VISITED(transport_);
EXPECT_UNVISITED(candidate_pair_);
EXPECT_UNVISITED(local_candidate_);
EXPECT_UNVISITED(remote_candidate_);
}
TEST_F(RTCStatsTraversalTest, BogusReference) {
transport_->rtcp_transport_stats_id = "bogus-reference";
TakeReferencedStats({transport_});
EXPECT_VISITED(transport_);
EXPECT_UNVISITED(candidate_pair_);
EXPECT_UNVISITED(local_candidate_);
EXPECT_UNVISITED(remote_candidate_);
}
TEST_F(RTCStatsTraversalTest, Tree) {
// start:candidate-pair
// | |
// v v
// local-candidate remote-candidate
// |
// v
// transport
candidate_pair_->local_candidate_id = "local-candidate";
candidate_pair_->remote_candidate_id = "remote-candidate";
local_candidate_->transport_id = "transport";
TakeReferencedStats({candidate_pair_});
EXPECT_VISITED(transport_);
EXPECT_VISITED(candidate_pair_);
EXPECT_VISITED(local_candidate_);
EXPECT_VISITED(remote_candidate_);
}
TEST_F(RTCStatsTraversalTest, MultiplePathsToSameNode) {
// start:candidate-pair
// | |
// v v
// local-candidate remote-candidate
// | |
// v v
// transport
candidate_pair_->local_candidate_id = "local-candidate";
candidate_pair_->remote_candidate_id = "remote-candidate";
local_candidate_->transport_id = "transport";
remote_candidate_->transport_id = "transport";
TakeReferencedStats({candidate_pair_});
EXPECT_VISITED(transport_);
EXPECT_VISITED(candidate_pair_);
EXPECT_VISITED(local_candidate_);
EXPECT_VISITED(remote_candidate_);
}
TEST_F(RTCStatsTraversalTest, CyclicGraph) {
// candidate-pair
// | ^
// v |
// start:local-candidate | remote-candidate
// | |
// v |
// transport
local_candidate_->transport_id = "transport";
transport_->selected_candidate_pair_id = "candidate-pair";
candidate_pair_->local_candidate_id = "local-candidate";
TakeReferencedStats({local_candidate_});
EXPECT_VISITED(transport_);
EXPECT_VISITED(candidate_pair_);
EXPECT_VISITED(local_candidate_);
EXPECT_UNVISITED(remote_candidate_);
}
TEST_F(RTCStatsTraversalTest, MultipleStarts) {
// start:candidate-pair
// |
// v
// local-candidate remote-candidate
// |
// v
// start:transport
candidate_pair_->remote_candidate_id = "remote-candidate";
local_candidate_->transport_id = "transport";
TakeReferencedStats({candidate_pair_, transport_});
EXPECT_VISITED(transport_);
EXPECT_VISITED(candidate_pair_);
EXPECT_UNVISITED(local_candidate_);
EXPECT_VISITED(remote_candidate_);
}
TEST_F(RTCStatsTraversalTest, MultipleStartsLeadingToSameNode) {
// candidate-pair
//
//
// start:local-candidate start:remote-candidate
// | |
// v v
// transport
local_candidate_->transport_id = "transport";
remote_candidate_->transport_id = "transport";
TakeReferencedStats({local_candidate_, remote_candidate_});
EXPECT_VISITED(transport_);
EXPECT_UNVISITED(candidate_pair_);
EXPECT_VISITED(local_candidate_);
EXPECT_VISITED(remote_candidate_);
}
} // namespace webrtc