1// Copyright 2013 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 <list>
6#include <string>
7
8#include "base/memory/scoped_ptr.h"
9#include "base/values.h"
10#include "chrome/test/chromedriver/chrome/heap_snapshot_taker.h"
11#include "chrome/test/chromedriver/chrome/status.h"
12#include "chrome/test/chromedriver/chrome/stub_devtools_client.h"
13#include "testing/gtest/include/gtest/gtest.h"
14
15namespace {
16
17const char* chunks[] = {"{\"a\": 1,", "\"b\": 2}"};
18
19scoped_ptr<base::Value> GetSnapshotAsValue() {
20  scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
21  dict->SetInteger("a", 1);
22  dict->SetInteger("b", 2);
23  return dict.PassAs<base::Value>();
24}
25
26class DummyDevToolsClient : public StubDevToolsClient {
27 public:
28  DummyDevToolsClient(const std::string& method, bool error_after_events)
29      : method_(method),
30        error_after_events_(error_after_events),
31        uid_(1),
32        disabled_(false) {}
33  virtual ~DummyDevToolsClient() {}
34
35  bool IsDisabled() { return disabled_; }
36
37  Status SendAddHeapSnapshotChunkEvent() {
38    base::DictionaryValue event_params;
39    event_params.SetInteger("uid", uid_);
40    for (size_t i = 0; i < arraysize(chunks); ++i) {
41      event_params.SetString("chunk", chunks[i]);
42      Status status = listeners_.front()->OnEvent(
43          this, "HeapProfiler.addHeapSnapshotChunk", event_params);
44      if (status.IsError())
45        return status;
46    }
47    return Status(kOk);
48  }
49
50  // Overridden from DevToolsClient:
51  virtual Status SendCommand(const std::string& method,
52                             const base::DictionaryValue& params) OVERRIDE {
53    if (!disabled_)
54      disabled_ = method == "Debugger.disable";
55    if (method == method_ && !error_after_events_)
56      return Status(kUnknownError);
57
58    if (method == "HeapProfiler.takeHeapSnapshot") {
59      Status status = SendAddHeapSnapshotChunkEvent();
60      if (status.IsError())
61        return status;
62    }
63
64    if (method == method_ && error_after_events_)
65      return Status(kUnknownError);
66    return StubDevToolsClient::SendCommand(method, params);
67  }
68
69 protected:
70  std::string method_;  // Throw error on command with this method.
71  bool error_after_events_;
72  int uid_;
73  bool disabled_;  // True if Debugger.disable was issued.
74};
75
76}  // namespace
77
78TEST(HeapSnapshotTaker, SuccessfulCase) {
79  DummyDevToolsClient client("", false);
80  HeapSnapshotTaker taker(&client);
81  scoped_ptr<base::Value> snapshot;
82  Status status = taker.TakeSnapshot(&snapshot);
83  ASSERT_EQ(kOk, status.code());
84  ASSERT_TRUE(GetSnapshotAsValue()->Equals(snapshot.get()));
85  ASSERT_TRUE(client.IsDisabled());
86}
87
88TEST(HeapSnapshotTaker, FailIfErrorOnDebuggerEnable) {
89  DummyDevToolsClient client("Debugger.enable", false);
90  HeapSnapshotTaker taker(&client);
91  scoped_ptr<base::Value> snapshot;
92  Status status = taker.TakeSnapshot(&snapshot);
93  ASSERT_TRUE(status.IsError());
94  ASSERT_FALSE(snapshot.get());
95  ASSERT_TRUE(client.IsDisabled());
96}
97
98TEST(HeapSnapshotTaker, FailIfErrorOnCollectGarbage) {
99  DummyDevToolsClient client("HeapProfiler.collectGarbage", false);
100  HeapSnapshotTaker taker(&client);
101  scoped_ptr<base::Value> snapshot;
102  Status status = taker.TakeSnapshot(&snapshot);
103  ASSERT_TRUE(status.IsError());
104  ASSERT_FALSE(snapshot.get());
105  ASSERT_TRUE(client.IsDisabled());
106}
107
108TEST(HeapSnapshotTaker, ErrorBeforeWhenReceivingSnapshot) {
109  DummyDevToolsClient client("HeapProfiler.takeHeapSnapshot", false);
110  HeapSnapshotTaker taker(&client);
111  scoped_ptr<base::Value> snapshot;
112  Status status = taker.TakeSnapshot(&snapshot);
113  ASSERT_TRUE(status.IsError());
114  ASSERT_FALSE(snapshot.get());
115  ASSERT_TRUE(client.IsDisabled());
116}
117
118