1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/metrics/plugin_metrics_provider.h"
6
7#include <string>
8
9#include "base/basictypes.h"
10#include "base/prefs/pref_service.h"
11#include "base/prefs/scoped_user_pref_update.h"
12#include "base/prefs/testing_pref_service.h"
13#include "base/run_loop.h"
14#include "base/strings/utf_string_conversions.h"
15#include "chrome/common/pref_names.h"
16#include "components/metrics/proto/system_profile.pb.h"
17#include "content/public/browser/child_process_data.h"
18#include "content/public/common/process_type.h"
19#include "content/public/common/webplugininfo.h"
20#include "content/public/test/test_browser_thread_bundle.h"
21#include "testing/gtest/include/gtest/gtest.h"
22
23namespace {
24
25content::WebPluginInfo CreateFakePluginInfo(
26    const std::string& name,
27    const base::FilePath::CharType* path,
28    const std::string& version,
29    bool is_pepper) {
30  content::WebPluginInfo plugin(base::UTF8ToUTF16(name),
31                                base::FilePath(path),
32                                base::UTF8ToUTF16(version),
33                                base::string16());
34  if (is_pepper)
35    plugin.type = content::WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS;
36  else
37    plugin.type = content::WebPluginInfo::PLUGIN_TYPE_NPAPI;
38  return plugin;
39}
40
41class PluginMetricsProviderTest : public ::testing::Test {
42 protected:
43  PluginMetricsProviderTest()
44      : prefs_(new TestingPrefServiceSimple) {
45    PluginMetricsProvider::RegisterPrefs(prefs()->registry());
46  }
47
48  TestingPrefServiceSimple* prefs() {
49    return prefs_.get();
50  }
51
52 private:
53  scoped_ptr<TestingPrefServiceSimple> prefs_;
54
55  DISALLOW_COPY_AND_ASSIGN(PluginMetricsProviderTest);
56};
57
58}  // namespace
59
60TEST_F(PluginMetricsProviderTest, IsPluginProcess) {
61  EXPECT_TRUE(PluginMetricsProvider::IsPluginProcess(
62      content::PROCESS_TYPE_PLUGIN));
63  EXPECT_TRUE(PluginMetricsProvider::IsPluginProcess(
64      content::PROCESS_TYPE_PPAPI_PLUGIN));
65  EXPECT_FALSE(PluginMetricsProvider::IsPluginProcess(
66      content::PROCESS_TYPE_GPU));
67}
68
69TEST_F(PluginMetricsProviderTest, Plugins) {
70  content::TestBrowserThreadBundle thread_bundle;
71
72  PluginMetricsProvider provider(prefs());
73
74  std::vector<content::WebPluginInfo> plugins;
75  plugins.push_back(CreateFakePluginInfo("p1", FILE_PATH_LITERAL("p1.plugin"),
76                                         "1.5", true));
77  plugins.push_back(CreateFakePluginInfo("p2", FILE_PATH_LITERAL("p2.plugin"),
78                                         "2.0", false));
79  provider.SetPluginsForTesting(plugins);
80
81  metrics::SystemProfileProto system_profile;
82  provider.ProvideSystemProfileMetrics(&system_profile);
83
84  ASSERT_EQ(2, system_profile.plugin_size());
85  EXPECT_EQ("p1", system_profile.plugin(0).name());
86  EXPECT_EQ("p1.plugin", system_profile.plugin(0).filename());
87  EXPECT_EQ("1.5", system_profile.plugin(0).version());
88  EXPECT_TRUE(system_profile.plugin(0).is_pepper());
89  EXPECT_EQ("p2", system_profile.plugin(1).name());
90  EXPECT_EQ("p2.plugin", system_profile.plugin(1).filename());
91  EXPECT_EQ("2.0", system_profile.plugin(1).version());
92  EXPECT_FALSE(system_profile.plugin(1).is_pepper());
93
94  // Now set some plugin stability stats for p2 and verify they're recorded.
95  scoped_ptr<base::DictionaryValue> plugin_dict(new base::DictionaryValue);
96  plugin_dict->SetString(prefs::kStabilityPluginName, "p2");
97  plugin_dict->SetInteger(prefs::kStabilityPluginLaunches, 1);
98  plugin_dict->SetInteger(prefs::kStabilityPluginCrashes, 2);
99  plugin_dict->SetInteger(prefs::kStabilityPluginInstances, 3);
100  plugin_dict->SetInteger(prefs::kStabilityPluginLoadingErrors, 4);
101  {
102    ListPrefUpdate update(prefs(), prefs::kStabilityPluginStats);
103    update.Get()->Append(plugin_dict.release());
104  }
105
106  provider.ProvideStabilityMetrics(&system_profile);
107
108  const metrics::SystemProfileProto_Stability& stability =
109      system_profile.stability();
110  ASSERT_EQ(1, stability.plugin_stability_size());
111  EXPECT_EQ("p2", stability.plugin_stability(0).plugin().name());
112  EXPECT_EQ("p2.plugin", stability.plugin_stability(0).plugin().filename());
113  EXPECT_EQ("2.0", stability.plugin_stability(0).plugin().version());
114  EXPECT_FALSE(stability.plugin_stability(0).plugin().is_pepper());
115  EXPECT_EQ(1, stability.plugin_stability(0).launch_count());
116  EXPECT_EQ(2, stability.plugin_stability(0).crash_count());
117  EXPECT_EQ(3, stability.plugin_stability(0).instance_count());
118  EXPECT_EQ(4, stability.plugin_stability(0).loading_error_count());
119}
120
121TEST_F(PluginMetricsProviderTest, RecordCurrentStateWithDelay) {
122  content::TestBrowserThreadBundle thread_bundle;
123
124  PluginMetricsProvider provider(prefs());
125
126  int delay_ms = 10;
127  EXPECT_TRUE(provider.RecordCurrentStateWithDelay(delay_ms));
128  EXPECT_FALSE(provider.RecordCurrentStateWithDelay(delay_ms));
129
130  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(delay_ms));
131  base::RunLoop().RunUntilIdle();
132
133  EXPECT_TRUE(provider.RecordCurrentStateWithDelay(delay_ms));
134}
135
136TEST_F(PluginMetricsProviderTest, RecordCurrentStateIfPending) {
137  content::TestBrowserThreadBundle thread_bundle;
138
139  PluginMetricsProvider provider(prefs());
140
141  // First there should be no need to force RecordCurrentState.
142  EXPECT_FALSE(provider.RecordCurrentStateIfPending());
143
144  // After delayed task is posted RecordCurrentStateIfPending should return
145  // true.
146  int delay_ms = 100000;
147  EXPECT_TRUE(provider.RecordCurrentStateWithDelay(delay_ms));
148  EXPECT_TRUE(provider.RecordCurrentStateIfPending());
149
150  // If RecordCurrentStateIfPending was successful then we should be able to
151  // post a new delayed task.
152  EXPECT_TRUE(provider.RecordCurrentStateWithDelay(delay_ms));
153}
154
155TEST_F(PluginMetricsProviderTest, ProvideStabilityMetricsWhenPendingTask) {
156  content::TestBrowserThreadBundle thread_bundle;
157
158  PluginMetricsProvider provider(prefs());
159
160  // Create plugin information for testing.
161  std::vector<content::WebPluginInfo> plugins;
162  plugins.push_back(CreateFakePluginInfo("p1", FILE_PATH_LITERAL("p1.plugin"),
163                                         "1.5", true));
164  provider.SetPluginsForTesting(plugins);
165  metrics::SystemProfileProto system_profile;
166  provider.ProvideSystemProfileMetrics(&system_profile);
167
168  // Increase number of created instances which should also start a delayed
169  // task.
170  content::ChildProcessData child_process_data(content::PROCESS_TYPE_PLUGIN);
171  child_process_data.name = base::UTF8ToUTF16("p1");
172  provider.BrowserChildProcessInstanceCreated(child_process_data);
173
174  // Call ProvideStabilityMetrics to check that it will force pending tasks to
175  // be executed immediately.
176  provider.ProvideStabilityMetrics(&system_profile);
177
178  // Check current number of instances created.
179  const metrics::SystemProfileProto_Stability& stability =
180      system_profile.stability();
181  EXPECT_EQ(1, stability.plugin_stability(0).instance_count());
182}
183