File: client_tracker_unittest.cc

package info (click to toggle)
chromium 139.0.7258.127-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,122,156 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (131 lines) | stat: -rw-r--r-- 4,572 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "components/exo/wayland/client_tracker.h"

#include <sys/socket.h>
#include <wayland-server-protocol-core.h>

#include "base/memory/raw_ptr.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace exo {
namespace wayland {

class WaylandClientTrackerTest : public testing::Test {
 protected:
  struct ClientData {
    raw_ptr<wl_client> client = nullptr;
    int fds[2] = {0, 0};
  };

  // testing::Test:
  void SetUp() override {
    testing::Test::SetUp();
    wayland_display_ = wl_display_create();
    client_tracker_ = std::make_unique<ClientTracker>(wayland_display_);
  }
  void TearDown() override {
    while (clients_.size() > 0) {
      DestroyClient(clients_.back().client);
    }
    client_tracker_.reset();
    wl_display_destroy(wayland_display_.ExtractAsDangling());
    testing::Test::TearDown();
  }

  // Creates a wl_client for this test's display.
  wl_client* CreateClient() {
    ClientData client_data;
    socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, client_data.fds);
    client_data.client = wl_client_create(wayland_display_, client_data.fds[0]);
    clients_.push_back(std::move(client_data));
    return clients_.back().client;
  }

  // Destroys the wl_client.
  void DestroyClient(wl_client* client) {
    auto it = std::find_if(
        clients_.begin(), clients_.end(),
        [&](const ClientData& data) { return data.client == client; });

    if (it != clients_.end()) {
      wl_client_destroy(it->client.ExtractAsDangling());
      close(it->fds[1]);
      clients_.erase(it);
    }
  }

  raw_ptr<wl_display> wayland_display_ = nullptr;
  std::unique_ptr<ClientTracker> client_tracker_;
  std::vector<ClientData> clients_;
};

// Tests that clients are tracked correctly when they are created and destroyed.
TEST_F(WaylandClientTrackerTest, ClientRegistersAndDeregistersSuccessfully) {
  EXPECT_EQ(0, client_tracker_->NumClientsTrackedForTesting());

  // Create two client, both should report as not destroyed.
  wl_client* client_1 = CreateClient();
  EXPECT_TRUE(client_1);
  EXPECT_EQ(1, client_tracker_->NumClientsTrackedForTesting());
  EXPECT_FALSE(client_tracker_->IsClientDestroyed(client_1));

  wl_client* client_2 = CreateClient();
  EXPECT_TRUE(client_2);
  EXPECT_EQ(2, client_tracker_->NumClientsTrackedForTesting());
  EXPECT_FALSE(client_tracker_->IsClientDestroyed(client_2));

  // Destroy the second client. It should have been removed from the client
  // tracker and the first client should still be tracked.
  DestroyClient(client_2);
  EXPECT_EQ(1, client_tracker_->NumClientsTrackedForTesting());
  EXPECT_FALSE(client_tracker_->IsClientDestroyed(client_1));

  // Destroy the first client, it should have been removed from the client
  // tracker.
  DestroyClient(client_1);
  EXPECT_EQ(0, client_tracker_->NumClientsTrackedForTesting());
}

// Simulate a situation where wayland will call back into test code after client
// destruction has started, but before the client destruction has finished.
// Assert that the client is reported as destroted after destruction has begun.
TEST_F(WaylandClientTrackerTest, ClientTaggedDestroyedAfterDestructionStarted) {
  wl_client* client = CreateClient();
  EXPECT_FALSE(client_tracker_->IsClientDestroyed(client));

  // Create a resource associated with the client. Attach user data and a
  // destructor to the resource.
  struct UserData {
    raw_ptr<ClientTracker> client_tracker = nullptr;
    raw_ptr<wl_client> client = nullptr;
  };
  UserData data = {.client_tracker = client_tracker_.get(), .client = client};

  wl_resource* output_resource =
      wl_resource_create(client, &wl_output_interface, 2, 0);
  wl_resource_set_user_data(output_resource, &data);

  // Assert that the client is no longer valid once destruction has begun and
  // the client's resources subsequently begin destruction.
  auto wl_resource_callback = [](wl_resource* resource) {
    UserData* data =
        static_cast<UserData*>(wl_resource_get_user_data(resource));
    EXPECT_TRUE(data->client_tracker->IsClientDestroyed(
        data->client.ExtractAsDangling()));
  };
  wl_resource_set_destructor(output_resource, wl_resource_callback);

  DestroyClient(client);
}

}  // namespace wayland
}  // namespace exo