midi_manager_unittest.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. // Copyright 2014 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. #include "media/midi/midi_manager.h"
  5. #include <stddef.h>
  6. #include <stdint.h>
  7. #include <memory>
  8. #include <vector>
  9. #include "base/bind.h"
  10. #include "base/check_op.h"
  11. #include "base/memory/weak_ptr.h"
  12. #include "base/run_loop.h"
  13. #include "base/system/system_monitor.h"
  14. #include "base/test/task_environment.h"
  15. #include "build/build_config.h"
  16. #include "media/midi/midi_service.h"
  17. #include "media/midi/task_service.h"
  18. #include "testing/gtest/include/gtest/gtest.h"
  19. #if BUILDFLAG(IS_WIN)
  20. #include "media/midi/midi_manager_win.h"
  21. #endif // BUILDFLAG(IS_WIN)
  22. namespace midi {
  23. namespace {
  24. using mojom::PortState;
  25. using mojom::Result;
  26. class FakeMidiManager : public MidiManager {
  27. public:
  28. explicit FakeMidiManager(MidiService* service) : MidiManager(service) {}
  29. FakeMidiManager(const FakeMidiManager&) = delete;
  30. FakeMidiManager& operator=(const FakeMidiManager&) = delete;
  31. ~FakeMidiManager() override = default;
  32. base::WeakPtr<FakeMidiManager> GetWeakPtr() {
  33. return weak_factory_.GetWeakPtr();
  34. }
  35. // MidiManager implementation.
  36. void StartInitialization() override {
  37. DCHECK(!initialized_);
  38. initialized_ = true;
  39. }
  40. void DispatchSendMidiData(MidiManagerClient* client,
  41. uint32_t port_index,
  42. const std::vector<uint8_t>& data,
  43. base::TimeTicks timestamp) override {}
  44. // Utility functions for testing.
  45. void CallCompleteInitialization(Result result) {
  46. CompleteInitialization(result);
  47. }
  48. size_t GetClientCount() { return GetClientCountForTesting(); }
  49. size_t GetPendingClientCount() { return GetPendingClientCountForTesting(); }
  50. bool IsInitialized() const { return initialized_; }
  51. private:
  52. bool initialized_ = false;
  53. base::WeakPtrFactory<FakeMidiManager> weak_factory_{this};
  54. };
  55. class FakeMidiManagerFactory : public MidiService::ManagerFactory {
  56. public:
  57. FakeMidiManagerFactory() {}
  58. FakeMidiManagerFactory(const FakeMidiManagerFactory&) = delete;
  59. FakeMidiManagerFactory& operator=(const FakeMidiManagerFactory&) = delete;
  60. ~FakeMidiManagerFactory() override = default;
  61. std::unique_ptr<MidiManager> Create(MidiService* service) override {
  62. std::unique_ptr<FakeMidiManager> manager =
  63. std::make_unique<FakeMidiManager>(service);
  64. manager_ = manager->GetWeakPtr();
  65. return manager;
  66. }
  67. base::WeakPtr<FakeMidiManagerFactory> GetWeakPtr() {
  68. return weak_factory_.GetWeakPtr();
  69. }
  70. base::WeakPtr<FakeMidiManager> manager() {
  71. #if BUILDFLAG(IS_MAC)
  72. // To avoid Core MIDI issues, MidiManager won't be destructed on macOS.
  73. // See https://crbug.com/718140.
  74. if (!manager_ ||
  75. (!manager_->GetClientCount() && !manager_->GetPendingClientCount())) {
  76. return nullptr;
  77. }
  78. #endif
  79. return manager_;
  80. }
  81. private:
  82. base::WeakPtr<FakeMidiManager> manager_ = nullptr;
  83. base::WeakPtrFactory<FakeMidiManagerFactory> weak_factory_{this};
  84. };
  85. class FakeMidiManagerClient : public MidiManagerClient {
  86. public:
  87. FakeMidiManagerClient() = default;
  88. FakeMidiManagerClient(const FakeMidiManagerClient&) = delete;
  89. FakeMidiManagerClient& operator=(const FakeMidiManagerClient&) = delete;
  90. ~FakeMidiManagerClient() override = default;
  91. // MidiManagerClient implementation.
  92. void AddInputPort(const mojom::PortInfo& info) override {}
  93. void AddOutputPort(const mojom::PortInfo& info) override {}
  94. void SetInputPortState(uint32_t port_index, PortState state) override {}
  95. void SetOutputPortState(uint32_t port_index, PortState state) override {}
  96. void CompleteStartSession(Result result) override {
  97. EXPECT_TRUE(wait_for_result_);
  98. result_ = result;
  99. wait_for_result_ = false;
  100. }
  101. void ReceiveMidiData(uint32_t port_index,
  102. const uint8_t* data,
  103. size_t size,
  104. base::TimeTicks timestamp) override {}
  105. void AccumulateMidiBytesSent(size_t size) override {}
  106. void Detach() override {}
  107. Result result() const { return result_; }
  108. Result WaitForResult() {
  109. while (wait_for_result_) {
  110. base::RunLoop run_loop;
  111. run_loop.RunUntilIdle();
  112. }
  113. return result();
  114. }
  115. private:
  116. Result result_ = Result::NOT_SUPPORTED;
  117. bool wait_for_result_ = true;
  118. };
  119. class MidiManagerTest : public ::testing::Test {
  120. public:
  121. MidiManagerTest() {
  122. std::unique_ptr<FakeMidiManagerFactory> factory =
  123. std::make_unique<FakeMidiManagerFactory>();
  124. factory_ = factory->GetWeakPtr();
  125. service_ = std::make_unique<MidiService>(std::move(factory));
  126. }
  127. MidiManagerTest(const MidiManagerTest&) = delete;
  128. MidiManagerTest& operator=(const MidiManagerTest&) = delete;
  129. ~MidiManagerTest() override {
  130. service_->Shutdown();
  131. base::RunLoop run_loop;
  132. run_loop.RunUntilIdle();
  133. }
  134. protected:
  135. void StartTheFirstSession(FakeMidiManagerClient* client) {
  136. DCHECK(factory_);
  137. EXPECT_FALSE(factory_->manager());
  138. service_->StartSession(client);
  139. ASSERT_TRUE(factory_->manager());
  140. EXPECT_TRUE(factory_->manager()->IsInitialized());
  141. EXPECT_EQ(0U, factory_->manager()->GetClientCount());
  142. EXPECT_EQ(1U, factory_->manager()->GetPendingClientCount());
  143. }
  144. void StartTheNthSession(FakeMidiManagerClient* client, size_t nth) {
  145. DCHECK(factory_);
  146. DCHECK_NE(1U, nth);
  147. ASSERT_TRUE(factory_->manager());
  148. EXPECT_TRUE(factory_->manager()->IsInitialized());
  149. EXPECT_EQ(0U, factory_->manager()->GetClientCount());
  150. EXPECT_EQ(nth - 1U, factory_->manager()->GetPendingClientCount());
  151. service_->StartSession(client);
  152. EXPECT_EQ(nth, factory_->manager()->GetPendingClientCount());
  153. }
  154. void StartSession(FakeMidiManagerClient* client) {
  155. service_->StartSession(client);
  156. }
  157. void EndSession(FakeMidiManagerClient* client, size_t before, size_t after) {
  158. DCHECK(factory_);
  159. ASSERT_TRUE(factory_->manager());
  160. EXPECT_EQ(before, factory_->manager()->GetClientCount());
  161. EXPECT_TRUE(service_->EndSession(client));
  162. if (after) {
  163. ASSERT_TRUE(factory_->manager());
  164. EXPECT_EQ(after, factory_->manager()->GetClientCount());
  165. } else {
  166. EXPECT_FALSE(factory_->manager());
  167. }
  168. }
  169. bool CompleteInitialization(Result result) {
  170. DCHECK(factory_);
  171. if (!factory_->manager())
  172. return false;
  173. factory_->manager()->CallCompleteInitialization(result);
  174. return true;
  175. }
  176. void RunLoopUntilIdle() {
  177. base::RunLoop run_loop;
  178. run_loop.RunUntilIdle();
  179. }
  180. base::WeakPtr<FakeMidiManagerFactory> factory() { return factory_; }
  181. private:
  182. base::test::TaskEnvironment env_;
  183. base::WeakPtr<FakeMidiManagerFactory> factory_;
  184. std::unique_ptr<MidiService> service_;
  185. };
  186. TEST_F(MidiManagerTest, StartAndEndSession) {
  187. std::unique_ptr<FakeMidiManagerClient> client =
  188. std::make_unique<FakeMidiManagerClient>();
  189. StartTheFirstSession(client.get());
  190. EXPECT_TRUE(CompleteInitialization(Result::OK));
  191. EXPECT_EQ(Result::OK, client->WaitForResult());
  192. EndSession(client.get(), 1U, 0U);
  193. }
  194. TEST_F(MidiManagerTest, StartAndEndSessionWithError) {
  195. std::unique_ptr<FakeMidiManagerClient> client =
  196. std::make_unique<FakeMidiManagerClient>();
  197. StartTheFirstSession(client.get());
  198. EXPECT_TRUE(CompleteInitialization(Result::INITIALIZATION_ERROR));
  199. EXPECT_EQ(Result::INITIALIZATION_ERROR, client->WaitForResult());
  200. EndSession(client.get(), 1U, 0U);
  201. }
  202. TEST_F(MidiManagerTest, StartMultipleSessions) {
  203. std::unique_ptr<FakeMidiManagerClient> client1 =
  204. std::make_unique<FakeMidiManagerClient>();
  205. std::unique_ptr<FakeMidiManagerClient> client2 =
  206. std::make_unique<FakeMidiManagerClient>();
  207. std::unique_ptr<FakeMidiManagerClient> client3 =
  208. std::make_unique<FakeMidiManagerClient>();
  209. StartTheFirstSession(client1.get());
  210. StartTheNthSession(client2.get(), 2);
  211. StartTheNthSession(client3.get(), 3);
  212. EXPECT_TRUE(CompleteInitialization(Result::OK));
  213. EXPECT_EQ(Result::OK, client1->WaitForResult());
  214. EXPECT_EQ(Result::OK, client2->WaitForResult());
  215. EXPECT_EQ(Result::OK, client3->WaitForResult());
  216. EndSession(client1.get(), 3U, 2U);
  217. EndSession(client2.get(), 2U, 1U);
  218. EndSession(client3.get(), 1U, 0U);
  219. }
  220. TEST_F(MidiManagerTest, TooManyPendingSessions) {
  221. // Push as many client requests for starting session as possible.
  222. std::vector<std::unique_ptr<FakeMidiManagerClient>> many_existing_clients;
  223. many_existing_clients.resize(MidiManager::kMaxPendingClientCount);
  224. many_existing_clients[0] = std::make_unique<FakeMidiManagerClient>();
  225. StartTheFirstSession(many_existing_clients[0].get());
  226. for (size_t i = 1; i < MidiManager::kMaxPendingClientCount; ++i) {
  227. many_existing_clients[i] = std::make_unique<FakeMidiManagerClient>();
  228. StartTheNthSession(many_existing_clients[i].get(), i + 1);
  229. }
  230. ASSERT_TRUE(factory()->manager());
  231. EXPECT_TRUE(factory()->manager()->IsInitialized());
  232. // Push the last client that should be rejected for too many pending requests.
  233. std::unique_ptr<FakeMidiManagerClient> additional_client =
  234. std::make_unique<FakeMidiManagerClient>();
  235. StartSession(additional_client.get());
  236. EXPECT_EQ(Result::INITIALIZATION_ERROR, additional_client->result());
  237. // Other clients still should not receive a result.
  238. RunLoopUntilIdle();
  239. for (size_t i = 0; i < many_existing_clients.size(); ++i)
  240. EXPECT_EQ(Result::NOT_SUPPORTED, many_existing_clients[i]->result());
  241. // The Result::OK should be distributed to other clients.
  242. EXPECT_TRUE(CompleteInitialization(Result::OK));
  243. for (size_t i = 0; i < many_existing_clients.size(); ++i)
  244. EXPECT_EQ(Result::OK, many_existing_clients[i]->WaitForResult());
  245. // Close all successful sessions in FIFO order.
  246. size_t sessions = many_existing_clients.size();
  247. for (size_t i = 0; i < many_existing_clients.size(); ++i, --sessions)
  248. EndSession(many_existing_clients[i].get(), sessions, sessions - 1);
  249. }
  250. TEST_F(MidiManagerTest, AbortSession) {
  251. // A client starting a session can be destructed while an asynchronous
  252. // initialization is performed.
  253. std::unique_ptr<FakeMidiManagerClient> client =
  254. std::make_unique<FakeMidiManagerClient>();
  255. StartTheFirstSession(client.get());
  256. EndSession(client.get(), 0, 0);
  257. client.reset();
  258. // Following function should not call the destructed |client| function.
  259. EXPECT_FALSE(CompleteInitialization(Result::OK));
  260. base::RunLoop run_loop;
  261. run_loop.RunUntilIdle();
  262. }
  263. class PlatformMidiManagerTest : public ::testing::Test {
  264. public:
  265. PlatformMidiManagerTest()
  266. : client_(std::make_unique<FakeMidiManagerClient>()),
  267. service_(std::make_unique<MidiService>()) {
  268. //
  269. }
  270. PlatformMidiManagerTest(const PlatformMidiManagerTest&) = delete;
  271. PlatformMidiManagerTest& operator=(const PlatformMidiManagerTest&) = delete;
  272. ~PlatformMidiManagerTest() override {
  273. service_->Shutdown();
  274. base::RunLoop run_loop;
  275. run_loop.RunUntilIdle();
  276. }
  277. MidiService* service() { return service_.get(); }
  278. void StartSession() { service_->StartSession(client_.get()); }
  279. void EndSession() { service_->EndSession(client_.get()); }
  280. Result WaitForResult() { return client_->WaitForResult(); }
  281. // This #ifdef needs to be identical to the one in media/midi/midi_manager.cc.
  282. // Do not change the condition for disabling this test.
  283. bool IsSupported() {
  284. #if !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_WIN) && \
  285. !(defined(USE_ALSA) && defined(USE_UDEV)) && !BUILDFLAG(IS_ANDROID)
  286. return false;
  287. #else
  288. return true;
  289. #endif
  290. }
  291. private:
  292. // SystemMonitor is needed on Windows.
  293. base::SystemMonitor system_monitor;
  294. base::test::TaskEnvironment env_;
  295. std::unique_ptr<FakeMidiManagerClient> client_;
  296. std::unique_ptr<MidiService> service_;
  297. };
  298. #if BUILDFLAG(IS_ANDROID)
  299. // The test sometimes fails on Android. https://crbug.com/844027
  300. #define MAYBE_CreatePlatformMidiManager DISABLED_CreatePlatformMidiManager
  301. #else
  302. #define MAYBE_CreatePlatformMidiManager CreatePlatformMidiManager
  303. #endif
  304. TEST_F(PlatformMidiManagerTest, MAYBE_CreatePlatformMidiManager) {
  305. StartSession();
  306. Result result = WaitForResult();
  307. #if defined(USE_ALSA)
  308. // Temporary until http://crbug.com/371230 is resolved.
  309. EXPECT_TRUE(result == Result::OK || result == Result::INITIALIZATION_ERROR);
  310. #else
  311. EXPECT_EQ(IsSupported() ? Result::OK : Result::NOT_SUPPORTED, result);
  312. #endif
  313. }
  314. TEST_F(PlatformMidiManagerTest, InstanceIdOverflow) {
  315. service()->task_service()->OverflowInstanceIdForTesting();
  316. #if BUILDFLAG(IS_WIN)
  317. MidiManagerWin::OverflowInstanceIdForTesting();
  318. #endif // BUILDFLAG(IS_WIN)
  319. StartSession();
  320. EXPECT_EQ(
  321. IsSupported() ? Result::INITIALIZATION_ERROR : Result::NOT_SUPPORTED,
  322. WaitForResult());
  323. EndSession();
  324. }
  325. } // namespace
  326. } // namespace midi