InputHub_test.cpp revision c929d2509530b0262681c8e6619609f44bfceea4
1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "InputHub_test"
18//#define LOG_NDEBUG 0
19
20#include <linux/input.h>
21
22#include <chrono>
23#include <memory>
24#include <mutex>
25
26#include <gtest/gtest.h>
27
28#include <utils/Log.h>
29#include <utils/StopWatch.h>
30#include <utils/Timers.h>
31
32#include "InputHub.h"
33#include "TestHelpers.h"
34
35// # of milliseconds to fudge stopwatch measurements
36#define TIMING_TOLERANCE_MS 25
37#define NO_TIMEOUT (-1)
38
39namespace android {
40namespace tests {
41
42using namespace std::literals::chrono_literals;
43
44using InputCbFunc = std::function<void(const std::shared_ptr<InputDeviceNode>&, InputEvent&, nsecs_t)>;
45using DeviceCbFunc = std::function<void(const std::shared_ptr<InputDeviceNode>&)>;
46
47static const InputCbFunc kNoopInputCb = [](const std::shared_ptr<InputDeviceNode>&, InputEvent&, nsecs_t){};
48static const DeviceCbFunc kNoopDeviceCb = [](const std::shared_ptr<InputDeviceNode>&){};
49
50class TestInputCallback : public InputCallbackInterface {
51public:
52    TestInputCallback() :
53        mInputCb(kNoopInputCb), mDeviceAddedCb(kNoopDeviceCb), mDeviceRemovedCb(kNoopDeviceCb) {}
54    virtual ~TestInputCallback() = default;
55
56    void setInputCallback(InputCbFunc cb) { mInputCb = cb; }
57    void setDeviceAddedCallback(DeviceCbFunc cb) { mDeviceAddedCb = cb; }
58    void setDeviceRemovedCallback(DeviceCbFunc cb) { mDeviceRemovedCb = cb; }
59
60    virtual void onInputEvent(const std::shared_ptr<InputDeviceNode>& node, InputEvent& event,
61            nsecs_t event_time) override {
62        mInputCb(node, event, event_time);
63    }
64    virtual void onDeviceAdded(const std::shared_ptr<InputDeviceNode>& node) override {
65        mDeviceAddedCb(node);
66    }
67    virtual void onDeviceRemoved(const std::shared_ptr<InputDeviceNode>& node) override {
68        mDeviceRemovedCb(node);
69    }
70
71private:
72    InputCbFunc mInputCb;
73    DeviceCbFunc mDeviceAddedCb;
74    DeviceCbFunc mDeviceRemovedCb;
75};
76
77class InputHubTest : public ::testing::Test {
78 protected:
79     virtual void SetUp() {
80         mCallback = std::make_shared<TestInputCallback>();
81         mInputHub = std::make_shared<InputHub>(mCallback);
82     }
83
84     std::shared_ptr<TestInputCallback> mCallback;
85     std::shared_ptr<InputHub> mInputHub;
86};
87
88TEST_F(InputHubTest, testWake) {
89    // Call wake() after 100ms.
90    auto f = delay_async(100ms, [&]() { EXPECT_EQ(OK, mInputHub->wake()); });
91
92    StopWatch stopWatch("poll");
93    EXPECT_EQ(OK, mInputHub->poll());
94    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
95
96    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
97}
98
99TEST_F(InputHubTest, DISABLED_testDeviceAdded) {
100    auto tempDir = std::make_shared<TempDir>();
101    std::string pathname;
102    // Expect that this callback will run and set handle and pathname.
103    mCallback->setDeviceAddedCallback(
104            [&](const std::shared_ptr<InputDeviceNode>& node) {
105                pathname = node->getPath();
106            });
107
108    ASSERT_EQ(OK, mInputHub->registerDevicePath(tempDir->getName()));
109
110    // Create a new file in tempDir after 100ms.
111    std::unique_ptr<TempFile> tempFile;
112    std::mutex tempFileMutex;
113    auto f = delay_async(100ms,
114            [&]() {
115                std::lock_guard<std::mutex> lock(tempFileMutex);
116                tempFile.reset(tempDir->newTempFile());
117            });
118
119    StopWatch stopWatch("poll");
120    EXPECT_EQ(OK, mInputHub->poll());
121    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
122
123
124    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
125    std::lock_guard<std::mutex> lock(tempFileMutex);
126    EXPECT_EQ(tempFile->getName(), pathname);
127}
128
129TEST_F(InputHubTest, DISABLED_testDeviceRemoved) {
130    // Create a temp dir and file. Save its name and handle (to be filled in
131    // once InputHub scans the dir).
132    auto tempDir = std::make_unique<TempDir>();
133    auto deviceFile = std::unique_ptr<TempFile>(tempDir->newTempFile());
134    std::string tempFileName(deviceFile->getName());
135
136    std::shared_ptr<InputDeviceNode> tempNode;
137    // Expect that these callbacks will run for the above device file.
138    mCallback->setDeviceAddedCallback(
139            [&](const std::shared_ptr<InputDeviceNode>& node) {
140                tempNode = node;
141            });
142    mCallback->setDeviceRemovedCallback(
143            [&](const std::shared_ptr<InputDeviceNode>& node) {
144                EXPECT_EQ(tempNode, node);
145            });
146
147    ASSERT_EQ(OK, mInputHub->registerDevicePath(tempDir->getName()));
148    // Ensure that tempDir was scanned to find the device.
149    ASSERT_TRUE(tempNode != nullptr);
150
151    auto f = delay_async(100ms, [&]() { deviceFile.reset(); });
152
153    StopWatch stopWatch("poll");
154    EXPECT_EQ(OK, mInputHub->poll());
155    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
156
157    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
158}
159
160TEST_F(InputHubTest, DISABLED_testInputEvent) {
161    // Create a temp dir and file. Save its name and handle (to be filled in
162    // once InputHub scans the dir.)
163    auto tempDir = std::make_unique<TempDir>();
164    auto deviceFile = std::unique_ptr<TempFile>(tempDir->newTempFile());
165    std::string tempFileName(deviceFile->getName());
166
167    // Send a key event corresponding to HOME.
168    struct input_event iev;
169    iev.time = { 1, 0 };
170    iev.type = EV_KEY;
171    iev.code = KEY_HOME;
172    iev.value = 0x01;
173
174    auto inputDelayMs = 100ms;
175    auto f = delay_async(inputDelayMs, [&] {
176                ssize_t nWrite = TEMP_FAILURE_RETRY(write(deviceFile->getFd(), &iev, sizeof(iev)));
177
178                ASSERT_EQ(static_cast<ssize_t>(sizeof(iev)), nWrite) << "could not write to "
179                    << deviceFile->getFd() << ". errno: " << errno;
180            });
181
182    // Expect this callback to run when the input event is read.
183    nsecs_t expectedWhen = systemTime(CLOCK_MONOTONIC) + ms2ns(inputDelayMs.count());
184    mCallback->setInputCallback(
185            [&](const std::shared_ptr<InputDeviceNode>& node, InputEvent& event,
186                nsecs_t event_time) {
187                EXPECT_NEAR(expectedWhen, event_time, ms2ns(TIMING_TOLERANCE_MS));
188                EXPECT_EQ(s2ns(1), event.when);
189                EXPECT_EQ(tempFileName, node->getPath());
190                EXPECT_EQ(EV_KEY, event.type);
191                EXPECT_EQ(KEY_HOME, event.code);
192                EXPECT_EQ(0x01, event.value);
193            });
194    ASSERT_EQ(OK, mInputHub->registerDevicePath(tempDir->getName()));
195
196    StopWatch stopWatch("poll");
197    EXPECT_EQ(OK, mInputHub->poll());
198    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
199
200    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
201}
202
203TEST_F(InputHubTest, DISABLED_testCallbackOrder) {
204    // Create two "devices": one to receive input and the other to go away.
205    auto tempDir = std::make_unique<TempDir>();
206    auto deviceFile1 = std::unique_ptr<TempFile>(tempDir->newTempFile());
207    auto deviceFile2 = std::unique_ptr<TempFile>(tempDir->newTempFile());
208    std::string tempFileName(deviceFile2->getName());
209
210    bool inputCallbackFinished = false, deviceCallbackFinished = false;
211
212    // Setup the callback for input events. Should run before the device
213    // callback.
214    mCallback->setInputCallback(
215            [&](const std::shared_ptr<InputDeviceNode>&, InputEvent&, nsecs_t) {
216                ASSERT_FALSE(deviceCallbackFinished);
217                inputCallbackFinished = true;
218            });
219
220    // Setup the callback for device removal. Should run after the input
221    // callback.
222    mCallback->setDeviceRemovedCallback(
223            [&](const std::shared_ptr<InputDeviceNode>& node) {
224                ASSERT_TRUE(inputCallbackFinished)
225                    << "input callback did not run before device changed callback";
226                // Make sure the correct device was removed.
227                EXPECT_EQ(tempFileName, node->getPath());
228                deviceCallbackFinished = true;
229            });
230    ASSERT_EQ(OK, mInputHub->registerDevicePath(tempDir->getName()));
231
232    auto f = delay_async(100ms,
233            [&]() {
234                // Delete the second device file first.
235                deviceFile2.reset();
236
237                // Then inject an input event into the first device.
238                struct input_event iev;
239                iev.time = { 1, 0 };
240                iev.type = EV_KEY;
241                iev.code = KEY_HOME;
242                iev.value = 0x01;
243
244                ssize_t nWrite = TEMP_FAILURE_RETRY(write(deviceFile1->getFd(), &iev, sizeof(iev)));
245
246                ASSERT_EQ(static_cast<ssize_t>(sizeof(iev)), nWrite) << "could not write to "
247                    << deviceFile1->getFd() << ". errno: " << errno;
248            });
249
250    StopWatch stopWatch("poll");
251    EXPECT_EQ(OK, mInputHub->poll());
252    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
253
254    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
255    EXPECT_TRUE(inputCallbackFinished);
256    EXPECT_TRUE(deviceCallbackFinished);
257}
258
259}  // namespace tests
260}  // namespace android
261