RTCStatsReport: Take ownership of other's stats with TakeMembersFrom
This would make it possible to gather stats on multiple threads, store
the results in multiple reports and to merge the results.
Added rtcstatsreport_unittest.cc, moving a RTCStatsReport-related test
from rtcstats_unittest.cc. Added more unittests covering the order of
stats and TakeMembersFrom.
Also changed RTCStatsReport[] to RTCStatsReport::Get to avoid
confusion with other usages of the [] operator.
BUG=chromium:627816
NOTRY=True
Review-Url: https://codereview.webrtc.org/2278433003
Cr-Commit-Position: refs/heads/master@{#13957}
diff --git a/webrtc/api/rtcstatsreport.h b/webrtc/api/rtcstatsreport.h
index 42237eb..fbd78b9 100644
--- a/webrtc/api/rtcstatsreport.h
+++ b/webrtc/api/rtcstatsreport.h
@@ -55,9 +55,13 @@
RTCStatsReport(const RTCStatsReport& other) = delete;
bool AddStats(std::unique_ptr<const RTCStats> stats);
- const RTCStats* operator[](const std::string& id) const;
+ const RTCStats* Get(const std::string& id) const;
size_t size() const { return stats_.size(); }
+ // Takes ownership of all the stats in |victim|, leaving it empty.
+ void TakeMembersFrom(rtc::scoped_refptr<RTCStatsReport> victim);
+
+ // Stats iterators. Stats are ordered lexicographically on |RTCStats::id|.
ConstIterator begin() const;
ConstIterator end() const;
diff --git a/webrtc/stats/BUILD.gn b/webrtc/stats/BUILD.gn
index 50f4351..2f69216 100644
--- a/webrtc/stats/BUILD.gn
+++ b/webrtc/stats/BUILD.gn
@@ -37,6 +37,7 @@
testonly = true
sources = [
"rtcstats_unittest.cc",
+ "rtcstatsreport_unittest.cc",
]
configs += [ "..:common_config" ]
diff --git a/webrtc/stats/rtcstats_unittest.cc b/webrtc/stats/rtcstats_unittest.cc
index 12364ae..44e75c4 100644
--- a/webrtc/stats/rtcstats_unittest.cc
+++ b/webrtc/stats/rtcstats_unittest.cc
@@ -9,11 +9,9 @@
*/
#include "webrtc/api/rtcstats.h"
-#include "webrtc/api/rtcstatsreport.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/gunit.h"
-#include "webrtc/base/logging.h"
namespace webrtc {
@@ -165,39 +163,6 @@
EXPECT_EQ(*copy.grandchild_int, *stats.grandchild_int);
}
-TEST(RTCStatsTest, TestRTCStatsReport) {
- rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create();
- EXPECT_EQ(report->size(), static_cast<size_t>(0));
- report->AddStats(std::unique_ptr<RTCStats>(new RTCTestStats("a0", 1.0)));
- report->AddStats(std::unique_ptr<RTCStats>(new RTCTestStats("a1", 2.0)));
- report->AddStats(std::unique_ptr<RTCStats>(new RTCChildStats("b0", 4.0)));
- report->AddStats(std::unique_ptr<RTCStats>(new RTCChildStats("b1", 8.0)));
- report->AddStats(std::unique_ptr<RTCStats>(new RTCTestStats("a2", 16.0)));
- report->AddStats(std::unique_ptr<RTCStats>(new RTCChildStats("b2", 32.0)));
- EXPECT_EQ(report->size(), static_cast<size_t>(6));
-
- EXPECT_EQ((*report)["missing"], nullptr);
- EXPECT_EQ((*report)["a0"]->id(), "a0");
- EXPECT_EQ((*report)["b2"]->id(), "b2");
-
- std::vector<const RTCTestStats*> a = report->GetStatsOfType<RTCTestStats>();
- EXPECT_EQ(a.size(), static_cast<size_t>(3));
- uint32_t mask = 0;
- for (const RTCTestStats* stats : a)
- mask |= static_cast<uint32_t>(stats->timestamp());
- EXPECT_EQ(mask, static_cast<uint32_t>(1 | 2 | 16));
-
- std::vector<const RTCChildStats*> b = report->GetStatsOfType<RTCChildStats>();
- EXPECT_EQ(b.size(), static_cast<size_t>(3));
- mask = 0;
- for (const RTCChildStats* stats : b)
- mask |= static_cast<uint32_t>(stats->timestamp());
- EXPECT_EQ(mask, static_cast<uint32_t>(4 | 8 | 32));
-
- EXPECT_EQ(report->GetStatsOfType<RTCGrandChildStats>().size(),
- static_cast<size_t>(0));
-}
-
// Death tests.
// Disabled on Android because death tests misbehave on Android, see
// base/test/gtest_util.h.
diff --git a/webrtc/stats/rtcstatsreport.cc b/webrtc/stats/rtcstatsreport.cc
index 870651d..00a55f4 100644
--- a/webrtc/stats/rtcstatsreport.cc
+++ b/webrtc/stats/rtcstatsreport.cc
@@ -66,13 +66,22 @@
std::move(stats))).second;
}
-const RTCStats* RTCStatsReport::operator[](const std::string& id) const {
+const RTCStats* RTCStatsReport::Get(const std::string& id) const {
StatsMap::const_iterator it = stats_.find(id);
if (it != stats_.cend())
return it->second.get();
return nullptr;
}
+void RTCStatsReport::TakeMembersFrom(
+ rtc::scoped_refptr<RTCStatsReport> victim) {
+ for (StatsMap::iterator it = victim->stats_.begin();
+ it != victim->stats_.end(); ++it) {
+ AddStats(std::unique_ptr<const RTCStats>(it->second.release()));
+ }
+ victim->stats_.clear();
+}
+
RTCStatsReport::ConstIterator RTCStatsReport::begin() const {
return ConstIterator(rtc::scoped_refptr<const RTCStatsReport>(this),
stats_.cbegin());
diff --git a/webrtc/stats/rtcstatsreport_unittest.cc b/webrtc/stats/rtcstatsreport_unittest.cc
new file mode 100644
index 0000000..b4722ab
--- /dev/null
+++ b/webrtc/stats/rtcstatsreport_unittest.cc
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2016 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 "webrtc/api/rtcstatsreport.h"
+
+#include "webrtc/api/rtcstats.h"
+#include "webrtc/base/checks.h"
+#include "webrtc/base/gunit.h"
+
+namespace webrtc {
+
+class RTCTestStats1 : public RTCStats {
+ public:
+ RTCTestStats1(const std::string& id, double timestamp)
+ : RTCStats(id, timestamp),
+ integer("integer") {}
+
+ WEBRTC_RTCSTATS_IMPL(RTCStats, RTCTestStats1,
+ &integer);
+
+ RTCStatsMember<int32_t> integer;
+};
+
+const char RTCTestStats1::kType[] = "test-stats-1";
+
+class RTCTestStats2 : public RTCStats {
+ public:
+ RTCTestStats2(const std::string& id, double timestamp)
+ : RTCStats(id, timestamp),
+ number("number") {}
+
+ WEBRTC_RTCSTATS_IMPL(RTCStats, RTCTestStats2,
+ &number);
+
+ RTCStatsMember<double> number;
+};
+
+const char RTCTestStats2::kType[] = "test-stats-2";
+
+class RTCTestStats3 : public RTCStats {
+ public:
+ RTCTestStats3(const std::string& id, double timestamp)
+ : RTCStats(id, timestamp),
+ string("string") {}
+
+ WEBRTC_RTCSTATS_IMPL(RTCStats, RTCTestStats3,
+ &string);
+
+ RTCStatsMember<std::string> string;
+};
+
+const char RTCTestStats3::kType[] = "test-stats-3";
+
+TEST(RTCStatsReport, AddAndGetStats) {
+ rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create();
+ EXPECT_EQ(report->size(), static_cast<size_t>(0));
+ report->AddStats(std::unique_ptr<RTCStats>(new RTCTestStats1("a0", 1.0)));
+ report->AddStats(std::unique_ptr<RTCStats>(new RTCTestStats1("a1", 2.0)));
+ report->AddStats(std::unique_ptr<RTCStats>(new RTCTestStats2("b0", 4.0)));
+ report->AddStats(std::unique_ptr<RTCStats>(new RTCTestStats2("b1", 8.0)));
+ report->AddStats(std::unique_ptr<RTCStats>(new RTCTestStats1("a2", 16.0)));
+ report->AddStats(std::unique_ptr<RTCStats>(new RTCTestStats2("b2", 32.0)));
+ EXPECT_EQ(report->size(), static_cast<size_t>(6));
+
+ EXPECT_EQ(report->Get("missing"), nullptr);
+ EXPECT_EQ(report->Get("a0")->id(), "a0");
+ EXPECT_EQ(report->Get("b2")->id(), "b2");
+
+ std::vector<const RTCTestStats1*> a = report->GetStatsOfType<RTCTestStats1>();
+ EXPECT_EQ(a.size(), static_cast<size_t>(3));
+ uint32_t mask = 0;
+ for (const RTCTestStats1* stats : a)
+ mask |= static_cast<uint32_t>(stats->timestamp());
+ EXPECT_EQ(mask, static_cast<uint32_t>(1 | 2 | 16));
+
+ std::vector<const RTCTestStats2*> b = report->GetStatsOfType<RTCTestStats2>();
+ EXPECT_EQ(b.size(), static_cast<size_t>(3));
+ mask = 0;
+ for (const RTCTestStats2* stats : b)
+ mask |= static_cast<uint32_t>(stats->timestamp());
+ EXPECT_EQ(mask, static_cast<uint32_t>(4 | 8 | 32));
+
+ EXPECT_EQ(report->GetStatsOfType<RTCTestStats3>().size(),
+ static_cast<size_t>(0));
+}
+
+TEST(RTCStatsReport, StatsOrder) {
+ rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create();
+ report->AddStats(std::unique_ptr<RTCStats>(new RTCTestStats1("C", 2.0)));
+ report->AddStats(std::unique_ptr<RTCStats>(new RTCTestStats1("D", 3.0)));
+ report->AddStats(std::unique_ptr<RTCStats>(new RTCTestStats2("B", 1.0)));
+ report->AddStats(std::unique_ptr<RTCStats>(new RTCTestStats2("A", 0.0)));
+ report->AddStats(std::unique_ptr<RTCStats>(new RTCTestStats2("E", 4.0)));
+ report->AddStats(std::unique_ptr<RTCStats>(new RTCTestStats2("F", 5.0)));
+ report->AddStats(std::unique_ptr<RTCStats>(new RTCTestStats2("G", 6.0)));
+ size_t i = 0;
+ for (const RTCStats& stats : *report) {
+ EXPECT_EQ(static_cast<size_t>(stats.timestamp()), i);
+ ++i;
+ }
+ EXPECT_EQ(i, static_cast<size_t>(7));
+}
+
+TEST(RTCStatsReport, TakeMembersFrom) {
+ rtc::scoped_refptr<RTCStatsReport> a = RTCStatsReport::Create();
+ a->AddStats(std::unique_ptr<RTCStats>(new RTCTestStats1("B", 1.0)));
+ a->AddStats(std::unique_ptr<RTCStats>(new RTCTestStats1("C", 2.0)));
+ a->AddStats(std::unique_ptr<RTCStats>(new RTCTestStats1("E", 4.0)));
+ rtc::scoped_refptr<RTCStatsReport> b = RTCStatsReport::Create();
+ b->AddStats(std::unique_ptr<RTCStats>(new RTCTestStats1("A", 0.0)));
+ b->AddStats(std::unique_ptr<RTCStats>(new RTCTestStats1("D", 3.0)));
+ b->AddStats(std::unique_ptr<RTCStats>(new RTCTestStats1("F", 5.0)));
+
+ a->TakeMembersFrom(b);
+ EXPECT_EQ(b->size(), static_cast<size_t>(0));
+ size_t i = 0;
+ for (const RTCStats& stats : *a) {
+ EXPECT_EQ(static_cast<size_t>(stats.timestamp()), i);
+ ++i;
+ }
+ EXPECT_EQ(i, static_cast<size_t>(6));
+}
+
+} // namespace webrtc
diff --git a/webrtc/stats/stats.gyp b/webrtc/stats/stats.gyp
index 9310aab..4c22557 100644
--- a/webrtc/stats/stats.gyp
+++ b/webrtc/stats/stats.gyp
@@ -37,6 +37,7 @@
],
'sources': [
'rtcstats_unittest.cc',
+ 'rtcstatsreport_unittest.cc',
],
},
],