Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(193)

Side by Side Diff: net/nqe/network_quality_estimator_unittest.cc

Issue 2690303011: Revert of NQE: Record the main frame metrics at transaction start (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/nqe/network_quality_estimator.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/nqe/network_quality_estimator.h" 5 #include "net/nqe/network_quality_estimator.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include <limits> 10 #include <limits>
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
52 const std::string& histogram, 52 const std::string& histogram,
53 int32_t bucket_min, 53 int32_t bucket_min,
54 int32_t expected_min_count_samples) { 54 int32_t expected_min_count_samples) {
55 std::vector<base::Bucket> buckets = 55 std::vector<base::Bucket> buckets =
56 histogram_tester->GetAllSamples(histogram); 56 histogram_tester->GetAllSamples(histogram);
57 int actual_count_samples = 0; 57 int actual_count_samples = 0;
58 for (const auto& bucket : buckets) { 58 for (const auto& bucket : buckets) {
59 if (bucket.min == bucket_min) 59 if (bucket.min == bucket_min)
60 actual_count_samples += bucket.count; 60 actual_count_samples += bucket.count;
61 } 61 }
62 EXPECT_LE(expected_min_count_samples, actual_count_samples) 62 EXPECT_LE(expected_min_count_samples, actual_count_samples);
63 << " histogram=" << histogram << " bucket_min=" << bucket_min
64 << " expected_min_count_samples=" << expected_min_count_samples;
65 } 63 }
66 64
67 } // namespace 65 } // namespace
68 66
69 namespace net { 67 namespace net {
70 68
71 namespace { 69 namespace {
72 70
73 class TestEffectiveConnectionTypeObserver 71 class TestEffectiveConnectionTypeObserver
74 : public NetworkQualityEstimator::EffectiveConnectionTypeObserver { 72 : public NetworkQualityEstimator::EffectiveConnectionTypeObserver {
(...skipping 1613 matching lines...) Expand 10 before | Expand all | Expand 10 after
1688 // interval, and that the observers are notified of any change. 1686 // interval, and that the observers are notified of any change.
1689 TEST(NetworkQualityEstimatorTest, MAYBE_TestEffectiveConnectionTypeObserver) { 1687 TEST(NetworkQualityEstimatorTest, MAYBE_TestEffectiveConnectionTypeObserver) {
1690 base::HistogramTester histogram_tester; 1688 base::HistogramTester histogram_tester;
1691 std::unique_ptr<base::SimpleTestTickClock> tick_clock( 1689 std::unique_ptr<base::SimpleTestTickClock> tick_clock(
1692 new base::SimpleTestTickClock()); 1690 new base::SimpleTestTickClock());
1693 base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get(); 1691 base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get();
1694 1692
1695 TestEffectiveConnectionTypeObserver observer; 1693 TestEffectiveConnectionTypeObserver observer;
1696 TestNetworkQualityEstimator estimator; 1694 TestNetworkQualityEstimator estimator;
1697 estimator.AddEffectiveConnectionTypeObserver(&observer); 1695 estimator.AddEffectiveConnectionTypeObserver(&observer);
1698 // |observer| may be notified as soon as it is added. Run the loop to so that
1699 // the notification to |observer| is finished.
1700 base::RunLoop().RunUntilIdle();
1701 estimator.SetTickClockForTesting(std::move(tick_clock)); 1696 estimator.SetTickClockForTesting(std::move(tick_clock));
1702 1697
1703 TestDelegate test_delegate; 1698 TestDelegate test_delegate;
1704 TestURLRequestContext context(true); 1699 TestURLRequestContext context(true);
1705 context.set_network_quality_estimator(&estimator); 1700 context.set_network_quality_estimator(&estimator);
1706 context.Init(); 1701 context.Init();
1707 1702
1708 EXPECT_EQ(0U, observer.effective_connection_types().size()); 1703 EXPECT_EQ(0U, observer.effective_connection_types().size());
1709 1704
1710 estimator.set_start_time_null_http_rtt( 1705 estimator.set_start_time_null_http_rtt(
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
1933 std::unique_ptr<base::SimpleTestTickClock> tick_clock( 1928 std::unique_ptr<base::SimpleTestTickClock> tick_clock(
1934 new base::SimpleTestTickClock()); 1929 new base::SimpleTestTickClock());
1935 base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get(); 1930 base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get();
1936 1931
1937 TestEffectiveConnectionTypeObserver observer; 1932 TestEffectiveConnectionTypeObserver observer;
1938 TestNetworkQualityEstimator estimator; 1933 TestNetworkQualityEstimator estimator;
1939 estimator.SetTickClockForTesting(std::move(tick_clock)); 1934 estimator.SetTickClockForTesting(std::move(tick_clock));
1940 estimator.SimulateNetworkChange(NetworkChangeNotifier::CONNECTION_WIFI, 1935 estimator.SimulateNetworkChange(NetworkChangeNotifier::CONNECTION_WIFI,
1941 "test"); 1936 "test");
1942 estimator.AddEffectiveConnectionTypeObserver(&observer); 1937 estimator.AddEffectiveConnectionTypeObserver(&observer);
1943 // |observer| may be notified as soon as it is added. Run the loop to so that
1944 // the notification to |observer| is finished.
1945 base::RunLoop().RunUntilIdle();
1946 1938
1947 TestDelegate test_delegate; 1939 TestDelegate test_delegate;
1948 TestURLRequestContext context(true); 1940 TestURLRequestContext context(true);
1949 context.set_network_quality_estimator(&estimator); 1941 context.set_network_quality_estimator(&estimator);
1950 context.Init(); 1942 context.Init();
1951 1943
1952 EXPECT_EQ(0U, observer.effective_connection_types().size()); 1944 EXPECT_EQ(0U, observer.effective_connection_types().size());
1953 1945
1954 estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_2G); 1946 estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_2G);
1955 tick_clock_ptr->Advance(base::TimeDelta::FromMinutes(60)); 1947 tick_clock_ptr->Advance(base::TimeDelta::FromMinutes(60));
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
2110 #define MAYBE_TestTCPSocketRTT DISABLED_TestTCPSocketRTT 2102 #define MAYBE_TestTCPSocketRTT DISABLED_TestTCPSocketRTT
2111 #endif 2103 #endif
2112 // Tests that the TCP socket notifies the Network Quality Estimator of TCP RTTs, 2104 // Tests that the TCP socket notifies the Network Quality Estimator of TCP RTTs,
2113 // which in turn notifies registered RTT observers. 2105 // which in turn notifies registered RTT observers.
2114 TEST(NetworkQualityEstimatorTest, MAYBE_TestTCPSocketRTT) { 2106 TEST(NetworkQualityEstimatorTest, MAYBE_TestTCPSocketRTT) {
2115 base::HistogramTester histogram_tester; 2107 base::HistogramTester histogram_tester;
2116 TestRTTObserver rtt_observer; 2108 TestRTTObserver rtt_observer;
2117 2109
2118 std::map<std::string, std::string> variation_params; 2110 std::map<std::string, std::string> variation_params;
2119 variation_params["persistent_cache_reading_enabled"] = "true"; 2111 variation_params["persistent_cache_reading_enabled"] = "true";
2120 TestNetworkQualityEstimator estimator( 2112 TestNetworkQualityEstimator estimator(variation_params);
2121 nullptr, variation_params, true, true,
2122 true /* add_default_platform_observations */,
2123 base::MakeUnique<BoundTestNetLog>());
2124 estimator.SimulateNetworkChange( 2113 estimator.SimulateNetworkChange(
2125 NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test"); 2114 NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test");
2126 2115
2127 estimator.AddRTTObserver(&rtt_observer); 2116 estimator.AddRTTObserver(&rtt_observer);
2128 // |observer| may be notified as soon as it is added. Run the loop to so that
2129 // the notification to |observer| is finished.
2130 base::RunLoop().RunUntilIdle();
2131 2117
2132 TestDelegate test_delegate; 2118 TestDelegate test_delegate;
2133 TestURLRequestContext context(true); 2119 TestURLRequestContext context(true);
2134 context.set_network_quality_estimator(&estimator); 2120 context.set_network_quality_estimator(&estimator);
2135 2121
2136 std::unique_ptr<HttpNetworkSession::Params> params( 2122 std::unique_ptr<HttpNetworkSession::Params> params(
2137 new HttpNetworkSession::Params); 2123 new HttpNetworkSession::Params);
2138 // |estimator| should be notified of TCP RTT observations. 2124 // |estimator| should be notified of TCP RTT observations.
2139 params->socket_performance_watcher_factory = 2125 params->socket_performance_watcher_factory =
2140 estimator.GetSocketPerformanceWatcherFactory(); 2126 estimator.GetSocketPerformanceWatcherFactory();
2141 context.set_http_network_session_params(std::move(params)); 2127 context.set_http_network_session_params(std::move(params));
2142 context.Init(); 2128 context.Init();
2143 2129
2144 EXPECT_EQ(0U, rtt_observer.observations().size()); 2130 EXPECT_EQ(0U, rtt_observer.observations().size());
2145 base::TimeDelta rtt; 2131 base::TimeDelta rtt;
2146 EXPECT_TRUE(estimator.GetRecentHttpRTT(base::TimeTicks(), &rtt)); 2132 EXPECT_FALSE(estimator.GetRecentHttpRTT(base::TimeTicks(), &rtt));
2147 EXPECT_TRUE(estimator.GetRecentTransportRTT(base::TimeTicks(), &rtt)); 2133 EXPECT_FALSE(estimator.GetRecentTransportRTT(base::TimeTicks(), &rtt));
2148 2134
2149 // Send two requests. Verify that the completion of each request generates at 2135 // Send two requests. Verify that the completion of each request generates at
2150 // least one TCP RTT observation. 2136 // least one TCP RTT observation.
2151 const size_t num_requests = 2; 2137 const size_t num_requests = 2;
2152 for (size_t i = 0; i < num_requests; ++i) { 2138 for (size_t i = 0; i < num_requests; ++i) {
2153 size_t before_count_tcp_rtt_observations = 0; 2139 size_t before_count_tcp_rtt_observations = 0;
2154 for (const auto& observation : rtt_observer.observations()) { 2140 for (const auto& observation : rtt_observer.observations()) {
2155 if (observation.source == NETWORK_QUALITY_OBSERVATION_SOURCE_TCP) 2141 if (observation.source == NETWORK_QUALITY_OBSERVATION_SOURCE_TCP)
2156 ++before_count_tcp_rtt_observations; 2142 ++before_count_tcp_rtt_observations;
2157 } 2143 }
(...skipping 24 matching lines...) Expand all
2182 histogram_tester.ExpectBucketCount("NQE.TransportRTT.Percentile50.2G", 2168 histogram_tester.ExpectBucketCount("NQE.TransportRTT.Percentile50.2G",
2183 rtt.InMilliseconds(), 1); 2169 rtt.InMilliseconds(), 1);
2184 histogram_tester.ExpectTotalCount("NQE.TransportRTT.Percentile10.2G", 1); 2170 histogram_tester.ExpectTotalCount("NQE.TransportRTT.Percentile10.2G", 1);
2185 histogram_tester.ExpectTotalCount("NQE.TransportRTT.Percentile50.2G", 1); 2171 histogram_tester.ExpectTotalCount("NQE.TransportRTT.Percentile50.2G", 1);
2186 histogram_tester.ExpectTotalCount("NQE.TransportRTT.Percentile90.2G", 1); 2172 histogram_tester.ExpectTotalCount("NQE.TransportRTT.Percentile90.2G", 1);
2187 histogram_tester.ExpectTotalCount("NQE.TransportRTT.Percentile100.2G", 1); 2173 histogram_tester.ExpectTotalCount("NQE.TransportRTT.Percentile100.2G", 1);
2188 2174
2189 // Verify that metrics are logged correctly on main-frame requests. 2175 // Verify that metrics are logged correctly on main-frame requests.
2190 histogram_tester.ExpectTotalCount("NQE.MainFrame.TransportRTT.Percentile50", 2176 histogram_tester.ExpectTotalCount("NQE.MainFrame.TransportRTT.Percentile50",
2191 num_requests); 2177 num_requests);
2192 histogram_tester.ExpectUniqueSample("NQE.EstimateAvailable.MainFrame.RTT", 1, 2178 histogram_tester.ExpectBucketCount("NQE.EstimateAvailable.MainFrame.RTT", 0,
2193 num_requests); 2179 1);
2180 histogram_tester.ExpectBucketCount("NQE.EstimateAvailable.MainFrame.RTT", 1,
2181 num_requests - 1);
2194 histogram_tester.ExpectUniqueSample( 2182 histogram_tester.ExpectUniqueSample(
2195 "NQE.EstimateAvailable.MainFrame.TransportRTT", 1, num_requests); 2183 "NQE.EstimateAvailable.MainFrame.TransportRTT", 1, num_requests);
2196 histogram_tester.ExpectUniqueSample("NQE.EstimateAvailable.MainFrame.Kbps", 1, 2184 histogram_tester.ExpectBucketCount("NQE.EstimateAvailable.MainFrame.Kbps", 0,
2197 num_requests); 2185 1);
2186 histogram_tester.ExpectBucketCount("NQE.EstimateAvailable.MainFrame.Kbps", 1,
2187 num_requests - 1);
2198 2188
2199 histogram_tester.ExpectTotalCount( 2189 histogram_tester.ExpectTotalCount(
2200 "NQE.MainFrame.TransportRTT.Percentile50.2G", num_requests); 2190 "NQE.MainFrame.TransportRTT.Percentile50.2G", num_requests);
2201 histogram_tester.ExpectTotalCount("NQE.MainFrame.EffectiveConnectionType", 2191 histogram_tester.ExpectTotalCount("NQE.MainFrame.EffectiveConnectionType",
2202 num_requests); 2192 num_requests);
2203 histogram_tester.ExpectTotalCount("NQE.MainFrame.EffectiveConnectionType.2G", 2193 histogram_tester.ExpectTotalCount("NQE.MainFrame.EffectiveConnectionType.2G",
2204 num_requests); 2194 num_requests);
2205 histogram_tester.ExpectBucketCount("NQE.MainFrame.EffectiveConnectionType.2G", 2195 histogram_tester.ExpectBucketCount("NQE.MainFrame.EffectiveConnectionType.2G",
2206 EFFECTIVE_CONNECTION_TYPE_UNKNOWN, 0); 2196 EFFECTIVE_CONNECTION_TYPE_UNKNOWN, 1);
2207 ExpectBucketCountAtLeast(&histogram_tester, "NQE.RTT.ObservationSource", 2197 ExpectBucketCountAtLeast(&histogram_tester, "NQE.RTT.ObservationSource",
2208 NETWORK_QUALITY_OBSERVATION_SOURCE_TCP, 1); 2198 NETWORK_QUALITY_OBSERVATION_SOURCE_TCP, 1);
2209 ExpectBucketCountAtLeast(&histogram_tester, "NQE.Kbps.ObservationSource", 2199 ExpectBucketCountAtLeast(&histogram_tester, "NQE.Kbps.ObservationSource",
2210 NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP, 1); 2200 NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP, 1);
2201 histogram_tester.ExpectBucketCount("NQE.MainFrame.EffectiveConnectionType.2G",
2202 EFFECTIVE_CONNECTION_TYPE_UNKNOWN, 1);
2211 EXPECT_LE(1u, 2203 EXPECT_LE(1u,
2212 histogram_tester 2204 histogram_tester
2213 .GetAllSamples("NQE.EffectiveConnectionType.OnECTComputation") 2205 .GetAllSamples("NQE.EffectiveConnectionType.OnECTComputation")
2214 .size()); 2206 .size());
2215 EXPECT_LE(1u, 2207 EXPECT_LE(1u,
2216 histogram_tester.GetAllSamples("NQE.TransportRTT.OnECTComputation") 2208 histogram_tester.GetAllSamples("NQE.TransportRTT.OnECTComputation")
2217 .size()); 2209 .size());
2218 EXPECT_LE(1u, 2210 EXPECT_LE(1u,
2219 histogram_tester.GetAllSamples("NQE.RTT.OnECTComputation").size()); 2211 histogram_tester.GetAllSamples("NQE.RTT.OnECTComputation").size());
2220 2212
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after
2556 estimator.set_recent_http_rtt(test.http_rtt); 2548 estimator.set_recent_http_rtt(test.http_rtt);
2557 estimator.set_start_time_null_downlink_throughput_kbps( 2549 estimator.set_start_time_null_downlink_throughput_kbps(
2558 test.downstream_throughput_kbps); 2550 test.downstream_throughput_kbps);
2559 estimator.set_rand_double(test.rand_double); 2551 estimator.set_rand_double(test.rand_double);
2560 2552
2561 TestDelegate test_delegate; 2553 TestDelegate test_delegate;
2562 TestURLRequestContext context(true); 2554 TestURLRequestContext context(true);
2563 context.set_network_quality_estimator(&estimator); 2555 context.set_network_quality_estimator(&estimator);
2564 context.Init(); 2556 context.Init();
2565 2557
2566 histogram_tester.ExpectTotalCount(
2567 "NQE.Correlation.ResourceLoadTime.0Kb_128Kb", 0);
2568
2569 // Start a main-frame request that should cause network quality estimator to 2558 // Start a main-frame request that should cause network quality estimator to
2570 // record the network quality at the last main frame request. 2559 // record the network quality at the last main frame request.
2571 std::unique_ptr<URLRequest> request_1(context.CreateRequest( 2560 std::unique_ptr<URLRequest> request_1(context.CreateRequest(
2572 estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate)); 2561 estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate));
2573 request_1->SetLoadFlags(request_1->load_flags() | 2562 request_1->SetLoadFlags(request_1->load_flags() |
2574 LOAD_MAIN_FRAME_DEPRECATED); 2563 LOAD_MAIN_FRAME_DEPRECATED);
2575 request_1->Start(); 2564 request_1->Start();
2576 base::RunLoop().Run(); 2565 base::RunLoop().Run();
2566 histogram_tester.ExpectTotalCount(
2567 "NQE.Correlation.ResourceLoadTime.0Kb_128Kb", 0);
2568
2569 // Start another main-frame request which should cause network quality
2570 // estimator to record the correlation UMA.
2571 std::unique_ptr<URLRequest> request_2(context.CreateRequest(
2572 estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate));
2573 request_2->Start();
2574 base::RunLoop().Run();
2577 2575
2578 if (test.rand_double >= test.correlation_logging_probability) { 2576 if (test.rand_double >= test.correlation_logging_probability) {
2579 histogram_tester.ExpectTotalCount( 2577 histogram_tester.ExpectTotalCount(
2580 "NQE.Correlation.ResourceLoadTime.0Kb_128Kb", 0); 2578 "NQE.Correlation.ResourceLoadTime.0Kb_128Kb", 0);
2581 continue; 2579 continue;
2582 } 2580 }
2583 if (!test.use_transport_rtt && 2581 if (!test.use_transport_rtt &&
2584 test.http_rtt == nqe::internal::InvalidRTT()) { 2582 test.http_rtt == nqe::internal::InvalidRTT()) {
2585 histogram_tester.ExpectTotalCount( 2583 histogram_tester.ExpectTotalCount(
2586 "NQE.Correlation.ResourceLoadTime.0Kb_128Kb", 0); 2584 "NQE.Correlation.ResourceLoadTime.0Kb_128Kb", 0);
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
2724 ForceEffectiveConnectionTypeThroughFieldTrial) { 2722 ForceEffectiveConnectionTypeThroughFieldTrial) {
2725 for (int i = 0; i < EFFECTIVE_CONNECTION_TYPE_LAST; ++i) { 2723 for (int i = 0; i < EFFECTIVE_CONNECTION_TYPE_LAST; ++i) {
2726 std::map<std::string, std::string> variation_params; 2724 std::map<std::string, std::string> variation_params;
2727 variation_params["force_effective_connection_type"] = 2725 variation_params["force_effective_connection_type"] =
2728 GetNameForEffectiveConnectionType( 2726 GetNameForEffectiveConnectionType(
2729 static_cast<EffectiveConnectionType>(i)); 2727 static_cast<EffectiveConnectionType>(i));
2730 TestNetworkQualityEstimator estimator(variation_params); 2728 TestNetworkQualityEstimator estimator(variation_params);
2731 2729
2732 TestEffectiveConnectionTypeObserver observer; 2730 TestEffectiveConnectionTypeObserver observer;
2733 estimator.AddEffectiveConnectionTypeObserver(&observer); 2731 estimator.AddEffectiveConnectionTypeObserver(&observer);
2734 // |observer| may be notified as soon as it is added. Run the loop to so
2735 // that the notification to |observer| is finished.
2736 base::RunLoop().RunUntilIdle();
2737 2732
2738 TestDelegate test_delegate; 2733 TestDelegate test_delegate;
2739 TestURLRequestContext context(true); 2734 TestURLRequestContext context(true);
2740 context.set_network_quality_estimator(&estimator); 2735 context.set_network_quality_estimator(&estimator);
2741 context.Init(); 2736 context.Init();
2742 2737
2743 EXPECT_EQ(0U, observer.effective_connection_types().size()); 2738 EXPECT_EQ(0U, observer.effective_connection_types().size());
2744 2739
2745 std::unique_ptr<URLRequest> request(context.CreateRequest( 2740 std::unique_ptr<URLRequest> request(context.CreateRequest(
2746 estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate)); 2741 estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate));
(...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after
3076 3071
3077 // Cleanup. 3072 // Cleanup.
3078 estimator.RemoveRTTObserver(&rtt_observer); 3073 estimator.RemoveRTTObserver(&rtt_observer);
3079 estimator.RemoveThroughputObserver(&throughput_observer); 3074 estimator.RemoveThroughputObserver(&throughput_observer);
3080 estimator.RemoveRTTAndThroughputEstimatesObserver(&rtt_throughput_observer); 3075 estimator.RemoveRTTAndThroughputEstimatesObserver(&rtt_throughput_observer);
3081 estimator.RemoveEffectiveConnectionTypeObserver( 3076 estimator.RemoveEffectiveConnectionTypeObserver(
3082 &effective_connection_type_observer); 3077 &effective_connection_type_observer);
3083 } 3078 }
3084 3079
3085 } // namespace net 3080 } // namespace net
OLDNEW
« no previous file with comments | « net/nqe/network_quality_estimator.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698