Chromium Code Reviews| Index: components/metrics/public/cpp/call_stack_profile_struct_traits_unittest.cc |
| diff --git a/components/metrics/public/cpp/call_stack_profile_struct_traits_unittest.cc b/components/metrics/public/cpp/call_stack_profile_struct_traits_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..9029ef6278235b26da4de12b3658bc9a89135241 |
| --- /dev/null |
| +++ b/components/metrics/public/cpp/call_stack_profile_struct_traits_unittest.cc |
| @@ -0,0 +1,204 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include <utility> |
| + |
| +#include "base/logging.h" |
| +#include "base/macros.h" |
| +#include "base/message_loop/message_loop.h" |
| +#include "components/metrics/public/interfaces/call_stack_profile_collector_test.mojom.h" |
| +#include "mojo/public/cpp/bindings/binding.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +namespace metrics { |
| + |
| +namespace { |
| + |
| +base::StackSamplingProfiler::CallStackProfile CreateProfile( |
| + const std::vector<base::StackSamplingProfiler::Module>& modules, |
| + const std::vector<base::StackSamplingProfiler::Sample>& samples, |
| + base::TimeDelta profile_duration, |
| + base::TimeDelta sampling_period) { |
| + base::StackSamplingProfiler::CallStackProfile profile; |
| + profile.modules = modules; |
| + profile.samples = samples; |
| + profile.profile_duration = profile_duration; |
| + profile.sampling_period = sampling_period; |
| + return profile; |
| +} |
| + |
| +} |
| + |
| +class CallStackProfileCollectorTestImpl |
| + : public mojom::CallStackProfileCollectorTest { |
| + public: |
| + explicit CallStackProfileCollectorTestImpl( |
| + mojo::InterfaceRequest<mojom::CallStackProfileCollectorTest> request) |
| + : binding_(this, std::move(request)) { |
| + } |
| + |
| + // CallStackProfileCollectorTest: |
| + void BounceFrame(const base::StackSamplingProfiler::Frame& in, |
| + const BounceFrameCallback& callback) override { |
| + callback.Run(in); |
| + } |
| + |
| + void BounceModule(const base::StackSamplingProfiler::Module& in, |
| + const BounceModuleCallback& callback) override { |
| + callback.Run(in); |
| + } |
| + |
| + void BounceProfile(const base::StackSamplingProfiler::CallStackProfile& in, |
| + const BounceProfileCallback& callback) override { |
| + callback.Run(in); |
| + } |
| + |
| + private: |
| + mojo::Binding<CallStackProfileCollectorTest> binding_; |
| +}; |
| + |
| +// Checks serialization/deserialization of Module fields. |
| +TEST(CallStackProfileStructTraitsTest, Module) { |
| + using Module = base::StackSamplingProfiler::Module; |
| + |
| + base::MessageLoop message_loop; |
|
Ilya Sherman
2016/08/18 07:59:18
nit: Why not declare this as part of the harness?
Mike Wittman
2016/08/18 17:49:19
Done.
|
| + |
| + mojom::CallStackProfileCollectorTestPtr proxy; |
| + CallStackProfileCollectorTestImpl impl(GetProxy(&proxy)); |
| + |
| + const Module serialize_cases[] = { |
| + Module(0x0, "abcd", base::FilePath(base::FilePath::kCurrentDirectory)), |
| + Module(0x10, "abcd", base::FilePath(base::FilePath::kCurrentDirectory)), |
| + Module(1ULL << (sizeof(uintptr_t) * 8) * 3 / 4, "abcd", |
| + base::FilePath(base::FilePath::kCurrentDirectory)), |
| + Module(0x10, "", base::FilePath(base::FilePath::kCurrentDirectory)), |
|
Ilya Sherman
2016/08/18 07:59:18
nit: It would be great to have a brief comment for
Mike Wittman
2016/08/18 17:49:19
Done.
|
| + }; |
| + |
| + for (const Module& input : serialize_cases) { |
| + Module output; |
| + EXPECT_TRUE(proxy->BounceModule(input, &output)); |
| + |
| + EXPECT_EQ(input.base_address, output.base_address); |
| + EXPECT_EQ(input.id, output.id); |
| + EXPECT_EQ(input.filename, output.filename); |
| + } |
| +} |
| + |
| +// Checks serialization/deserialization of Frame fields. |
| +TEST(CallStackProfileStructTraitsTest, Frame) { |
| + using Frame = base::StackSamplingProfiler::Frame; |
| + |
| + base::MessageLoop message_loop; |
| + |
| + mojom::CallStackProfileCollectorTestPtr proxy; |
| + CallStackProfileCollectorTestImpl impl(GetProxy(&proxy)); |
| + |
| + const Frame serialize_cases[] = { |
| + Frame(0x0, 10), |
| + Frame(0x10, 10), |
| + Frame(1ULL << (sizeof(uintptr_t) * 8) * 3 / 4, 10), |
| + Frame(0xabcd, 0), |
| + Frame(0xabcd, 1), |
| + Frame(0xabcd, 10), |
| + Frame(0xabcd, Frame::kUnknownModuleIndex), |
| + }; |
| + |
| + for (const Frame& input : serialize_cases) { |
| + Frame output; |
| + EXPECT_TRUE(proxy->BounceFrame(input, &output)); |
| + |
| + EXPECT_EQ(input.instruction_pointer, output.instruction_pointer); |
| + EXPECT_EQ(input.module_index, output.module_index); |
| + } |
| +} |
| + |
| +// Checks serialization/deserialization of Profile fields, including validation |
| +// of the Frame module_index field. |
| +TEST(CallStackProfileStructTraitsTest, Profile) { |
| + using Module = base::StackSamplingProfiler::Module; |
| + using Frame = base::StackSamplingProfiler::Frame; |
| + using Sample = base::StackSamplingProfiler::Sample; |
| + using Profile = base::StackSamplingProfiler::CallStackProfile; |
|
Ilya Sherman
2016/08/18 07:59:18
Hmm, why not write these using statements at the t
Mike Wittman
2016/08/18 17:49:19
The code under test is translating between two set
|
| + |
| + base::MessageLoop message_loop; |
| + |
| + mojom::CallStackProfileCollectorTestPtr proxy; |
| + CallStackProfileCollectorTestImpl impl(GetProxy(&proxy)); |
| + |
| + struct SerializeCase { |
| + Profile profile; |
| + bool expect_success; |
| + }; |
| + const SerializeCase serialize_cases[] = { |
| + { |
| + CreateProfile(std::vector<Module>(), std::vector<Sample>(), |
| + base::TimeDelta::FromSeconds(1), |
| + base::TimeDelta::FromSeconds(2)), |
| + true |
| + }, |
| + { |
| + CreateProfile({ Module(0x4000, "a", base::FilePath()) }, |
| + std::vector<Sample>(), |
| + base::TimeDelta::FromSeconds(1), |
| + base::TimeDelta::FromSeconds(2)), |
| + true |
| + }, |
| + { |
| + CreateProfile({ |
| + Module(0x4000, "a", base::FilePath()), |
| + Module(0x4100, "b", base::FilePath()), |
| + }, |
| + { |
| + { |
| + Frame(0x4010, 0), |
| + Frame(0x4110, 1), |
| + Frame(0x4110, Frame::kUnknownModuleIndex), |
| + } |
| + }, |
| + base::TimeDelta::FromSeconds(1), |
| + base::TimeDelta::FromSeconds(2)), |
| + true |
| + }, |
| + // The out of range module index in the second sample should cause the |
| + // entire deserialization to fail. |
| + { |
| + CreateProfile({ |
| + Module(0x4000, "a", base::FilePath()), |
| + Module(0x4100, "b", base::FilePath()), |
| + }, |
| + { |
| + { |
| + Frame(0x4010, 0), |
| + Frame(0x4110, 1), |
| + Frame(0x4110, Frame::kUnknownModuleIndex), |
| + }, |
| + { |
| + Frame(0x4010, 0), |
| + Frame(0x4110, 2), |
| + }, |
| + }, |
| + base::TimeDelta::FromSeconds(1), |
| + base::TimeDelta::FromSeconds(2)), |
| + false |
| + }, |
| + }; |
| + |
| + for (const SerializeCase& input : serialize_cases) { |
| + SCOPED_TRACE(&input - &serialize_cases[0]); |
| + |
| + Profile output; |
| + EXPECT_EQ(input.expect_success, |
| + proxy->BounceProfile(input.profile, &output)); |
| + |
| + if (!input.expect_success) |
| + continue; |
| + |
| + EXPECT_EQ(input.profile.modules, output.modules); |
| + EXPECT_EQ(input.profile.samples, output.samples); |
| + EXPECT_EQ(input.profile.profile_duration, output.profile_duration); |
| + EXPECT_EQ(input.profile.sampling_period, output.sampling_period); |
| + } |
| +} |
| + |
| +} // namespace metrics |