| Ana Krulec | 0c8cd52 | 2018-08-31 12:27:28 -0700 | [diff] [blame] | 1 | #undef LOG_TAG | 
|  | 2 | #define LOG_TAG "SchedulerUnittests" | 
|  | 3 |  | 
|  | 4 | #include <gmock/gmock.h> | 
|  | 5 | #include <gtest/gtest.h> | 
|  | 6 |  | 
|  | 7 | #include <log/log.h> | 
|  | 8 |  | 
| Ana Krulec | e588e31 | 2018-09-18 12:32:24 -0700 | [diff] [blame] | 9 | #include <mutex> | 
|  | 10 |  | 
| Ana Krulec | 0c8cd52 | 2018-08-31 12:27:28 -0700 | [diff] [blame] | 11 | #include "AsyncCallRecorder.h" | 
|  | 12 | #include "Scheduler/DispSync.h" | 
| Ana Krulec | e588e31 | 2018-09-18 12:32:24 -0700 | [diff] [blame] | 13 | #include "Scheduler/EventControlThread.h" | 
| Ana Krulec | 0c8cd52 | 2018-08-31 12:27:28 -0700 | [diff] [blame] | 14 | #include "Scheduler/EventThread.h" | 
|  | 15 | #include "Scheduler/Scheduler.h" | 
|  | 16 | #include "mock/MockDispSync.h" | 
|  | 17 | #include "mock/MockEventThread.h" | 
|  | 18 |  | 
|  | 19 | using testing::_; | 
|  | 20 | using testing::Return; | 
|  | 21 |  | 
|  | 22 | namespace android { | 
|  | 23 |  | 
|  | 24 | class SchedulerTest : public testing::Test { | 
|  | 25 | protected: | 
|  | 26 | class MockEventThreadConnection : public BnDisplayEventConnection { | 
|  | 27 | public: | 
|  | 28 | MockEventThreadConnection() = default; | 
|  | 29 | ~MockEventThreadConnection() = default; | 
|  | 30 |  | 
|  | 31 | MOCK_METHOD1(stealReceiveChannel, status_t(gui::BitTube* outChannel)); | 
|  | 32 | MOCK_METHOD1(setVsyncRate, status_t(uint32_t count)); | 
|  | 33 | MOCK_METHOD0(requestNextVsync, void()); | 
|  | 34 | }; | 
|  | 35 |  | 
|  | 36 | /** | 
|  | 37 | * This mock Scheduler class uses implementation of mock::EventThread but keeps everything else | 
|  | 38 | * the same. | 
|  | 39 | */ | 
|  | 40 | class MockScheduler : public android::Scheduler { | 
|  | 41 | public: | 
|  | 42 | MockScheduler(std::unique_ptr<EventThread> eventThread) | 
| Ana Krulec | e588e31 | 2018-09-18 12:32:24 -0700 | [diff] [blame] | 43 | : Scheduler([](bool) {}), mEventThread(std::move(eventThread)) {} | 
| Ana Krulec | 0c8cd52 | 2018-08-31 12:27:28 -0700 | [diff] [blame] | 44 |  | 
|  | 45 | std::unique_ptr<EventThread> makeEventThread( | 
| Ana Krulec | 1f02791 | 2018-09-10 21:36:25 +0000 | [diff] [blame] | 46 | const std::string& /* connectionName */, DispSync* /* dispSync */, | 
| Ana Krulec | 0c8cd52 | 2018-08-31 12:27:28 -0700 | [diff] [blame] | 47 | nsecs_t /* phaseOffsetNs */, | 
|  | 48 | impl::EventThread::ResyncWithRateLimitCallback /* resyncCallback */, | 
|  | 49 | impl::EventThread::InterceptVSyncsCallback /* interceptCallback */) override { | 
|  | 50 | return std::move(mEventThread); | 
|  | 51 | } | 
|  | 52 |  | 
|  | 53 | MockScheduler() = default; | 
|  | 54 | ~MockScheduler() override = default; | 
|  | 55 |  | 
|  | 56 | std::unique_ptr<EventThread> mEventThread; | 
|  | 57 | }; | 
|  | 58 |  | 
|  | 59 | SchedulerTest(); | 
|  | 60 | ~SchedulerTest() override; | 
|  | 61 |  | 
|  | 62 | sp<Scheduler::ConnectionHandle> mConnectionHandle; | 
|  | 63 | mock::DispSync* mPrimaryDispSync = new mock::DispSync(); | 
|  | 64 | mock::EventThread* mEventThread; | 
|  | 65 | std::unique_ptr<MockScheduler> mScheduler; | 
|  | 66 | sp<MockEventThreadConnection> mEventThreadConnection; | 
|  | 67 |  | 
|  | 68 | AsyncCallRecorder<void (*)()> mResyncCallRecorder; | 
|  | 69 | AsyncCallRecorder<void (*)(nsecs_t)> mInterceptVSyncCallRecorder; | 
|  | 70 | }; | 
|  | 71 |  | 
|  | 72 | SchedulerTest::SchedulerTest() { | 
|  | 73 | const ::testing::TestInfo* const test_info = | 
|  | 74 | ::testing::UnitTest::GetInstance()->current_test_info(); | 
|  | 75 | ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); | 
|  | 76 |  | 
|  | 77 | std::unique_ptr<mock::EventThread> eventThread = std::make_unique<mock::EventThread>(); | 
|  | 78 | mEventThread = eventThread.get(); | 
|  | 79 | mScheduler = std::make_unique<MockScheduler>(std::move(eventThread)); | 
|  | 80 | mEventThreadConnection = new MockEventThreadConnection(); | 
|  | 81 |  | 
|  | 82 | // createConnection call to scheduler makes a createEventConnection call to EventThread. Make | 
|  | 83 | // sure that call gets executed and returns an EventThread::Connection object. | 
|  | 84 | EXPECT_CALL(*mEventThread, createEventConnection()) | 
|  | 85 | .WillRepeatedly(Return(mEventThreadConnection)); | 
|  | 86 |  | 
| Ana Krulec | e588e31 | 2018-09-18 12:32:24 -0700 | [diff] [blame] | 87 | mConnectionHandle = | 
|  | 88 | mScheduler->createConnection("appConnection", 16, mResyncCallRecorder.getInvocable(), | 
|  | 89 | mInterceptVSyncCallRecorder.getInvocable()); | 
| Ana Krulec | 0c8cd52 | 2018-08-31 12:27:28 -0700 | [diff] [blame] | 90 | } | 
|  | 91 |  | 
|  | 92 | SchedulerTest::~SchedulerTest() { | 
|  | 93 | const ::testing::TestInfo* const test_info = | 
|  | 94 | ::testing::UnitTest::GetInstance()->current_test_info(); | 
|  | 95 | ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); | 
|  | 96 | } | 
|  | 97 |  | 
|  | 98 | namespace { | 
|  | 99 | /* ------------------------------------------------------------------------ | 
|  | 100 | * Test cases | 
|  | 101 | */ | 
|  | 102 | TEST_F(SchedulerTest, canCreateAndDestroyTest) { | 
|  | 103 | EXPECT_FALSE(mResyncCallRecorder.waitForCall().has_value()); | 
|  | 104 | EXPECT_FALSE(mInterceptVSyncCallRecorder.waitForCall().has_value()); | 
|  | 105 | EXPECT_EQ(0, mConnectionHandle->id); | 
|  | 106 | } | 
|  | 107 |  | 
|  | 108 | TEST_F(SchedulerTest, testNullPtr) { | 
|  | 109 | // Passing a null pointer for ConnectionHandle is a valid argument. The code doesn't throw any | 
|  | 110 | // exceptions, just gracefully continues. | 
|  | 111 | sp<IDisplayEventConnection> returnedValue; | 
|  | 112 | ASSERT_NO_FATAL_FAILURE(returnedValue = mScheduler->createDisplayEventConnection(nullptr)); | 
|  | 113 | EXPECT_TRUE(returnedValue == nullptr); | 
|  | 114 | EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr); | 
|  | 115 | EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr); | 
|  | 116 | ASSERT_NO_FATAL_FAILURE( | 
|  | 117 | mScheduler->hotplugReceived(nullptr, EventThread::DisplayType::Primary, false)); | 
|  | 118 | ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(nullptr)); | 
|  | 119 | ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(nullptr)); | 
|  | 120 | String8 testString; | 
|  | 121 | ASSERT_NO_FATAL_FAILURE(mScheduler->dump(nullptr, testString)); | 
|  | 122 | EXPECT_TRUE(testString == ""); | 
|  | 123 | ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(nullptr, 10)); | 
|  | 124 | } | 
|  | 125 |  | 
|  | 126 | TEST_F(SchedulerTest, invalidConnectionHandle) { | 
|  | 127 | // Passing an invalid ConnectionHandle is a valid argument. The code doesn't throw any | 
|  | 128 | // exceptions, just gracefully continues. | 
|  | 129 | sp<Scheduler::ConnectionHandle> connectionHandle = new Scheduler::ConnectionHandle(20); | 
|  | 130 |  | 
|  | 131 | sp<IDisplayEventConnection> returnedValue; | 
|  | 132 | ASSERT_NO_FATAL_FAILURE(returnedValue = | 
|  | 133 | mScheduler->createDisplayEventConnection(connectionHandle)); | 
|  | 134 | EXPECT_TRUE(returnedValue == nullptr); | 
|  | 135 | EXPECT_TRUE(mScheduler->getEventThread(connectionHandle) == nullptr); | 
|  | 136 | EXPECT_TRUE(mScheduler->getEventConnection(connectionHandle) == nullptr); | 
|  | 137 |  | 
|  | 138 | // The EXPECT_CALLS make sure we don't call the functions on the subsequent event threads. | 
|  | 139 | EXPECT_CALL(*mEventThread, onHotplugReceived(_, _)).Times(0); | 
|  | 140 | ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(connectionHandle, | 
|  | 141 | EventThread::DisplayType::Primary, false)); | 
|  | 142 |  | 
|  | 143 | EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(0); | 
|  | 144 | ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(connectionHandle)); | 
|  | 145 |  | 
|  | 146 | EXPECT_CALL(*mEventThread, onScreenReleased()).Times(0); | 
|  | 147 | ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(connectionHandle)); | 
|  | 148 |  | 
|  | 149 | String8 testString; | 
|  | 150 | EXPECT_CALL(*mEventThread, dump(_)).Times(0); | 
|  | 151 | ASSERT_NO_FATAL_FAILURE(mScheduler->dump(connectionHandle, testString)); | 
|  | 152 | EXPECT_TRUE(testString == ""); | 
|  | 153 |  | 
|  | 154 | EXPECT_CALL(*mEventThread, setPhaseOffset(_)).Times(0); | 
|  | 155 | ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(connectionHandle, 10)); | 
|  | 156 | } | 
|  | 157 |  | 
|  | 158 | TEST_F(SchedulerTest, validConnectionHandle) { | 
|  | 159 | sp<IDisplayEventConnection> returnedValue; | 
|  | 160 | ASSERT_NO_FATAL_FAILURE(returnedValue = | 
|  | 161 | mScheduler->createDisplayEventConnection(mConnectionHandle)); | 
|  | 162 | EXPECT_TRUE(returnedValue != nullptr); | 
|  | 163 | ASSERT_EQ(returnedValue, mEventThreadConnection); | 
|  | 164 |  | 
|  | 165 | EXPECT_TRUE(mScheduler->getEventThread(mConnectionHandle) != nullptr); | 
|  | 166 | EXPECT_TRUE(mScheduler->getEventConnection(mConnectionHandle) != nullptr); | 
|  | 167 |  | 
|  | 168 | EXPECT_CALL(*mEventThread, onHotplugReceived(EventThread::DisplayType::Primary, false)) | 
|  | 169 | .Times(1); | 
|  | 170 | ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(mConnectionHandle, | 
|  | 171 | EventThread::DisplayType::Primary, false)); | 
|  | 172 |  | 
|  | 173 | EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(1); | 
|  | 174 | ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(mConnectionHandle)); | 
|  | 175 |  | 
|  | 176 | EXPECT_CALL(*mEventThread, onScreenReleased()).Times(1); | 
|  | 177 | ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(mConnectionHandle)); | 
|  | 178 |  | 
|  | 179 | String8 testString("dump"); | 
|  | 180 | EXPECT_CALL(*mEventThread, dump(testString)).Times(1); | 
|  | 181 | ASSERT_NO_FATAL_FAILURE(mScheduler->dump(mConnectionHandle, testString)); | 
|  | 182 | EXPECT_TRUE(testString != ""); | 
|  | 183 |  | 
|  | 184 | EXPECT_CALL(*mEventThread, setPhaseOffset(10)).Times(1); | 
|  | 185 | ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(mConnectionHandle, 10)); | 
|  | 186 | } | 
|  | 187 |  | 
|  | 188 | } // namespace | 
|  | 189 | } // namespace android |