delegated_frame_resource_collection_unittest.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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 "base/bind.h"
6#include "base/run_loop.h"
7#include "base/synchronization/waitable_event.h"
8#include "base/threading/thread.h"
9#include "cc/layers/delegated_frame_resource_collection.h"
10#include "cc/resources/returned_resource.h"
11#include "cc/resources/transferable_resource.h"
12#include "testing/gtest/include/gtest/gtest.h"
13
14namespace cc {
15namespace {
16
17class DelegatedFrameResourceCollectionTest
18    : public testing::Test,
19      public DelegatedFrameResourceCollectionClient {
20 protected:
21  DelegatedFrameResourceCollectionTest() : resources_available_(false) {}
22
23  virtual void SetUp() OVERRIDE { CreateResourceCollection(); }
24
25  virtual void TearDown() OVERRIDE { DestroyResourceCollection(); }
26
27  void CreateResourceCollection() {
28    DCHECK(!resource_collection_);
29    resource_collection_ = new DelegatedFrameResourceCollection;
30    resource_collection_->SetClient(this);
31  }
32
33  void DestroyResourceCollection() {
34    if (resource_collection_) {
35      resource_collection_->SetClient(NULL);
36      resource_collection_ = NULL;
37    }
38  }
39
40  TransferableResourceArray CreateResourceArray() {
41    TransferableResourceArray resources;
42    TransferableResource resource;
43    resource.id = 444;
44    resources.push_back(resource);
45    return resources;
46  }
47
48  virtual void UnusedResourcesAreAvailable() OVERRIDE {
49    resources_available_ = true;
50    resource_collection_->TakeUnusedResourcesForChildCompositor(
51        &returned_resources_);
52    if (!resources_available_closure_.is_null())
53      resources_available_closure_.Run();
54  }
55
56  bool ReturnAndResetResourcesAvailable() {
57    bool r = resources_available_;
58    resources_available_ = false;
59    return r;
60  }
61
62  scoped_refptr<DelegatedFrameResourceCollection> resource_collection_;
63  bool resources_available_;
64  ReturnedResourceArray returned_resources_;
65  base::Closure resources_available_closure_;
66};
67
68// This checks that taking the return callback doesn't take extra refcounts,
69// since it's sent to other threads.
70TEST_F(DelegatedFrameResourceCollectionTest, NoRef) {
71  // Start with one ref.
72  EXPECT_TRUE(resource_collection_->HasOneRef());
73
74  ReturnCallback return_callback =
75      resource_collection_->GetReturnResourcesCallbackForImplThread();
76
77  // Callback shouldn't take a ref since it's sent to other threads.
78  EXPECT_TRUE(resource_collection_->HasOneRef());
79}
80
81void ReturnResourcesOnThread(ReturnCallback callback,
82                             const ReturnedResourceArray& resources,
83                             base::WaitableEvent* event) {
84  callback.Run(resources);
85  event->Wait();
86}
87
88// Tests that the ReturnCallback can run safely on threads even after the
89// last references to the collection were dropped.
90// Flaky: crbug.com/313441
91TEST_F(DelegatedFrameResourceCollectionTest, DISABLED_Thread) {
92  base::Thread thread("test thread");
93  thread.Start();
94
95  TransferableResourceArray resources = CreateResourceArray();
96  resource_collection_->ReceivedResources(resources);
97  resource_collection_->RefResources(resources);
98
99  ReturnedResourceArray returned_resources;
100  TransferableResource::ReturnResources(resources, &returned_resources);
101
102  base::WaitableEvent event(false, false);
103
104  {
105    base::RunLoop run_loop;
106    resources_available_closure_ = run_loop.QuitClosure();
107
108    thread.message_loop()->PostTask(
109        FROM_HERE,
110        base::Bind(
111            &ReturnResourcesOnThread,
112            resource_collection_->GetReturnResourcesCallbackForImplThread(),
113            returned_resources,
114            &event));
115
116    run_loop.Run();
117  }
118  EXPECT_TRUE(ReturnAndResetResourcesAvailable());
119  EXPECT_EQ(1u, returned_resources_.size());
120  EXPECT_EQ(444u, returned_resources_[0].id);
121  EXPECT_EQ(1, returned_resources_[0].count);
122  returned_resources_.clear();
123
124  // The event prevents the return resources callback from being deleted.
125  // Destroy the last reference from this thread to the collection before
126  // signaling the event, to ensure any reference taken by the callback, if any,
127  // would be the last one.
128  DestroyResourceCollection();
129  event.Signal();
130
131  CreateResourceCollection();
132  resource_collection_->ReceivedResources(resources);
133  resource_collection_->RefResources(resources);
134
135  // Destroy the collection before we have a chance to run the return callback.
136  ReturnCallback return_callback =
137      resource_collection_->GetReturnResourcesCallbackForImplThread();
138  resource_collection_->LoseAllResources();
139  DestroyResourceCollection();
140
141  EXPECT_TRUE(ReturnAndResetResourcesAvailable());
142  EXPECT_EQ(1u, returned_resources_.size());
143  EXPECT_EQ(444u, returned_resources_[0].id);
144  EXPECT_EQ(1, returned_resources_[0].count);
145  EXPECT_TRUE(returned_resources_[0].lost);
146  returned_resources_.clear();
147
148  thread.message_loop()->PostTask(FROM_HERE,
149                                  base::Bind(&ReturnResourcesOnThread,
150                                             return_callback,
151                                             returned_resources,
152                                             &event));
153  event.Signal();
154
155  thread.Stop();
156}
157
158}  // namespace
159}  // namespace cc
160