1 // Copyright (c) 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.
5 #include "components/browser_watcher/exit_funnel_win.h"
9 #include "base/command_line.h"
10 #include "base/process/process_handle.h"
11 #include "base/strings/string16.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/test/test_reg_util_win.h"
15 #include "base/threading/platform_thread.h"
16 #include "base/time/time.h"
17 #include "base/win/registry.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 namespace browser_watcher
{
24 const wchar_t kRegistryPath
[] = L
"Software\\ExitFunnelWinTest";
26 class ExitFunnelWinTest
: public testing::Test
{
28 typedef testing::Test Super
;
29 typedef std::map
<base::string16
, int64
> EventMap
;
31 void SetUp() override
{
34 override_manager_
.OverrideRegistry(HKEY_CURRENT_USER
);
37 base::string16
GetEventSubkey() {
38 // There should be a single subkey named after this process' pid.
39 base::win::RegistryKeyIterator
it(HKEY_CURRENT_USER
, kRegistryPath
);
40 EXPECT_EQ(1, it
.SubkeyCount());
43 base::StringToUint(it
.Name(), &pid
);
44 EXPECT_EQ(base::GetCurrentProcId(), pid
);
49 // TODO(siggi): Reuse the reading code from the metrics provider.
50 EventMap
ReadEventsFromSubkey(const base::string16
& subkey_name
) {
51 base::string16
key_name(
52 base::StringPrintf(L
"%ls\\%ls", kRegistryPath
, subkey_name
.c_str()));
54 base::win::RegKey
key(HKEY_CURRENT_USER
, key_name
.c_str(), KEY_READ
);
55 EXPECT_TRUE(key
.Valid());
56 EXPECT_EQ(2, key
.GetValueCount());
59 for (size_t i
= 0; i
< key
.GetValueCount(); ++i
) {
61 EXPECT_EQ(key
.GetValueNameAt(i
, &name
), ERROR_SUCCESS
);
63 EXPECT_EQ(key
.ReadInt64(name
.c_str(), &value
), ERROR_SUCCESS
);
71 EventMap
ReadEvents() {
72 base::string16 name
= GetEventSubkey();
73 return ReadEventsFromSubkey(name
);
77 registry_util::RegistryOverrideManager override_manager_
;
82 TEST_F(ExitFunnelWinTest
, RecordSingleEvent
) {
83 // Record a couple of events.
84 ASSERT_TRUE(ExitFunnel::RecordSingleEvent(kRegistryPath
, L
"One"));
85 ASSERT_TRUE(ExitFunnel::RecordSingleEvent(kRegistryPath
, L
"Two"));
87 EventMap events
= ReadEvents();
89 ASSERT_EQ(events
.size(), 2);
90 ASSERT_TRUE(events
.find(L
"One") != events
.end());
91 ASSERT_TRUE(events
.find(L
"Two") != events
.end());
94 TEST_F(ExitFunnelWinTest
, RecordsEventTimes
) {
97 ASSERT_TRUE(funnel
.Init(kRegistryPath
, base::GetCurrentProcessHandle()));
98 ASSERT_TRUE(funnel
.RecordEvent(L
"One"));
100 // Sleep for half a second to space the events in time.
101 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50));
103 ASSERT_TRUE(funnel
.RecordEvent(L
"Two"));
105 EventMap events
= ReadEvents();
106 ASSERT_EQ(events
.size(), 2);
108 base::TimeDelta one
= base::TimeDelta::FromInternalValue(events
[L
"One"]);
109 base::TimeDelta two
= base::TimeDelta::FromInternalValue(events
[L
"Two"]);
111 // Sleep is not accurate, it may over or under sleep. To minimize flakes,
112 // this test only compares relative ordering of the events.
116 } // namespace browser_watcher