| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 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 <utility> | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #include "base/macros.h" | |
| 9 #include "base/message_loop/message_loop.h" | |
| 10 #include "components/metrics/public/interfaces/call_stack_profile_collector_test
.mojom.h" | |
| 11 #include "mojo/public/cpp/bindings/binding.h" | |
| 12 #include "testing/gtest/include/gtest/gtest.h" | |
| 13 | |
| 14 namespace metrics { | |
| 15 | |
| 16 namespace { | |
| 17 | |
| 18 base::StackSamplingProfiler::CallStackProfile CreateProfile( | |
| 19 const std::vector<base::StackSamplingProfiler::Module>& modules, | |
| 20 const std::vector<base::StackSamplingProfiler::Sample>& samples, | |
| 21 base::TimeDelta profile_duration, | |
| 22 base::TimeDelta sampling_period) { | |
| 23 base::StackSamplingProfiler::CallStackProfile profile; | |
| 24 profile.modules = modules; | |
| 25 profile.samples = samples; | |
| 26 profile.profile_duration = profile_duration; | |
| 27 profile.sampling_period = sampling_period; | |
| 28 return profile; | |
| 29 } | |
| 30 | |
| 31 } | |
| 32 | |
| 33 class CallStackProfileCollectorTestImpl | |
| 34 : public mojom::CallStackProfileCollectorTest { | |
| 35 public: | |
| 36 explicit CallStackProfileCollectorTestImpl( | |
| 37 mojo::InterfaceRequest<mojom::CallStackProfileCollectorTest> request) | |
| 38 : binding_(this, std::move(request)) { | |
| 39 } | |
| 40 | |
| 41 // CallStackProfileCollectorTest: | |
| 42 void BounceFrame(const base::StackSamplingProfiler::Frame& in, | |
| 43 const BounceFrameCallback& callback) override { | |
| 44 callback.Run(in); | |
| 45 } | |
| 46 | |
| 47 void BounceModule(const base::StackSamplingProfiler::Module& in, | |
| 48 const BounceModuleCallback& callback) override { | |
| 49 callback.Run(in); | |
| 50 } | |
| 51 | |
| 52 void BounceProfile(const base::StackSamplingProfiler::CallStackProfile& in, | |
| 53 const BounceProfileCallback& callback) override { | |
| 54 callback.Run(in); | |
| 55 } | |
| 56 | |
| 57 private: | |
| 58 mojo::Binding<CallStackProfileCollectorTest> binding_; | |
| 59 | |
| 60 DISALLOW_COPY_AND_ASSIGN(CallStackProfileCollectorTestImpl); | |
| 61 }; | |
| 62 | |
| 63 class CallStackProfileStructTraitsTest : public testing::Test { | |
| 64 public: | |
| 65 CallStackProfileStructTraitsTest() : impl_(GetProxy(&proxy_)) {} | |
| 66 | |
| 67 protected: | |
| 68 base::MessageLoop message_loop_; | |
| 69 mojom::CallStackProfileCollectorTestPtr proxy_; | |
| 70 CallStackProfileCollectorTestImpl impl_; | |
| 71 | |
| 72 DISALLOW_COPY_AND_ASSIGN(CallStackProfileStructTraitsTest); | |
| 73 }; | |
| 74 | |
| 75 // Checks serialization/deserialization of Module fields. | |
| 76 TEST_F(CallStackProfileStructTraitsTest, Module) { | |
| 77 using Module = base::StackSamplingProfiler::Module; | |
| 78 | |
| 79 struct SerializeCase { | |
| 80 Module module; | |
| 81 bool expect_success; | |
| 82 }; | |
| 83 | |
| 84 const SerializeCase serialize_cases[] = { | |
| 85 // Null base address. | |
| 86 { | |
| 87 Module(0x0, "abcd", base::FilePath(base::FilePath::kCurrentDirectory)), | |
| 88 true | |
| 89 }, | |
| 90 // Non-null base address. | |
| 91 { | |
| 92 Module(0x10, "abcd", base::FilePath(base::FilePath::kCurrentDirectory)), | |
| 93 true | |
| 94 }, | |
| 95 // Base address with a bit set beyond 32 bits, when built for x64. | |
| 96 { | |
| 97 Module(1ULL << (sizeof(uintptr_t) * 8) * 3 / 4, "abcd", | |
| 98 base::FilePath(base::FilePath::kCurrentDirectory)), | |
| 99 true | |
| 100 }, | |
| 101 // Empty module id. | |
| 102 { | |
| 103 Module(0x10, "", base::FilePath(base::FilePath::kCurrentDirectory)), | |
| 104 true | |
| 105 }, | |
| 106 // Module id at the length limit. | |
| 107 { | |
| 108 Module(0x10, std::string(40, ' '), | |
| 109 base::FilePath(base::FilePath::kCurrentDirectory)), | |
| 110 true | |
| 111 }, | |
| 112 // Module id beyond the length limit. | |
| 113 { | |
| 114 Module(0x10, std::string(41, ' '), | |
| 115 base::FilePath(base::FilePath::kCurrentDirectory)), | |
| 116 false | |
| 117 }, | |
| 118 }; | |
| 119 | |
| 120 for (const SerializeCase& input : serialize_cases) { | |
| 121 Module output; | |
| 122 EXPECT_EQ(input.expect_success, | |
| 123 proxy_->BounceModule(input.module, &output)); | |
| 124 | |
| 125 if (!input.expect_success) | |
| 126 continue; | |
| 127 | |
| 128 EXPECT_EQ(input.module.base_address, output.base_address); | |
| 129 EXPECT_EQ(input.module.id, output.id); | |
| 130 EXPECT_EQ(input.module.filename, output.filename); | |
| 131 } | |
| 132 } | |
| 133 | |
| 134 // Checks serialization/deserialization of Frame fields. | |
| 135 TEST_F(CallStackProfileStructTraitsTest, Frame) { | |
| 136 using Frame = base::StackSamplingProfiler::Frame; | |
| 137 | |
| 138 const Frame serialize_cases[] = { | |
| 139 // Null instruction pointer. | |
| 140 Frame(0x0, 10), | |
| 141 // Non-null instruction pointer. | |
| 142 Frame(0x10, 10), | |
| 143 // Instruction pointer with a bit set beyond 32 bits, when built for x64. | |
| 144 Frame(1ULL << (sizeof(uintptr_t) * 8) * 3 / 4, 10), | |
| 145 // Zero module index. | |
| 146 Frame(0xabcd, 0), | |
| 147 // Non-zero module index. | |
| 148 Frame(0xabcd, 1), | |
| 149 // Non-zero module index. | |
| 150 Frame(0xabcd, 10), | |
| 151 // Unknown module index. | |
| 152 Frame(0xabcd, Frame::kUnknownModuleIndex), | |
| 153 }; | |
| 154 | |
| 155 for (const Frame& input : serialize_cases) { | |
| 156 Frame output; | |
| 157 EXPECT_TRUE(proxy_->BounceFrame(input, &output)); | |
| 158 | |
| 159 EXPECT_EQ(input.instruction_pointer, output.instruction_pointer); | |
| 160 EXPECT_EQ(input.module_index, output.module_index); | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 // Checks serialization/deserialization of Profile fields, including validation | |
| 165 // of the Frame module_index field. | |
| 166 TEST_F(CallStackProfileStructTraitsTest, Profile) { | |
| 167 using Module = base::StackSamplingProfiler::Module; | |
| 168 using Frame = base::StackSamplingProfiler::Frame; | |
| 169 using Sample = base::StackSamplingProfiler::Sample; | |
| 170 using Profile = base::StackSamplingProfiler::CallStackProfile; | |
| 171 | |
| 172 struct SerializeCase { | |
| 173 Profile profile; | |
| 174 bool expect_success; | |
| 175 }; | |
| 176 | |
| 177 const SerializeCase serialize_cases[] = { | |
| 178 // Empty modules and samples. | |
| 179 { | |
| 180 CreateProfile(std::vector<Module>(), std::vector<Sample>(), | |
| 181 base::TimeDelta::FromSeconds(1), | |
| 182 base::TimeDelta::FromSeconds(2)), | |
| 183 true | |
| 184 }, | |
| 185 // Non-empty modules and empty samples. | |
| 186 { | |
| 187 CreateProfile({ Module(0x4000, "a", base::FilePath()) }, | |
| 188 std::vector<Sample>(), | |
| 189 base::TimeDelta::FromSeconds(1), | |
| 190 base::TimeDelta::FromSeconds(2)), | |
| 191 true | |
| 192 }, | |
| 193 // Valid values for modules and samples. | |
| 194 { | |
| 195 CreateProfile({ | |
| 196 Module(0x4000, "a", base::FilePath()), | |
| 197 Module(0x4100, "b", base::FilePath()), | |
| 198 }, | |
| 199 { | |
| 200 { | |
| 201 Frame(0x4010, 0), | |
| 202 Frame(0x4110, 1), | |
| 203 Frame(0x4110, Frame::kUnknownModuleIndex), | |
| 204 } | |
| 205 }, | |
| 206 base::TimeDelta::FromSeconds(1), | |
| 207 base::TimeDelta::FromSeconds(2)), | |
| 208 true | |
| 209 }, | |
| 210 // Valid values for modules, but an out of range module index in the second | |
| 211 // sample. | |
| 212 { | |
| 213 CreateProfile({ | |
| 214 Module(0x4000, "a", base::FilePath()), | |
| 215 Module(0x4100, "b", base::FilePath()), | |
| 216 }, | |
| 217 { | |
| 218 { | |
| 219 Frame(0x4010, 0), | |
| 220 Frame(0x4110, 1), | |
| 221 Frame(0x4110, Frame::kUnknownModuleIndex), | |
| 222 }, | |
| 223 { | |
| 224 Frame(0x4010, 0), | |
| 225 Frame(0x4110, 2), | |
| 226 }, | |
| 227 }, | |
| 228 base::TimeDelta::FromSeconds(1), | |
| 229 base::TimeDelta::FromSeconds(2)), | |
| 230 false | |
| 231 }, | |
| 232 }; | |
| 233 | |
| 234 for (const SerializeCase& input : serialize_cases) { | |
| 235 SCOPED_TRACE(&input - &serialize_cases[0]); | |
| 236 | |
| 237 Profile output; | |
| 238 EXPECT_EQ(input.expect_success, | |
| 239 proxy_->BounceProfile(input.profile, &output)); | |
| 240 | |
| 241 if (!input.expect_success) | |
| 242 continue; | |
| 243 | |
| 244 EXPECT_EQ(input.profile.modules, output.modules); | |
| 245 EXPECT_EQ(input.profile.samples, output.samples); | |
| 246 EXPECT_EQ(input.profile.profile_duration, output.profile_duration); | |
| 247 EXPECT_EQ(input.profile.sampling_period, output.sampling_period); | |
| 248 } | |
| 249 } | |
| 250 | |
| 251 } // namespace metrics | |
| OLD | NEW |