blob: 0c77dda3d79535bbaf601cc2f1b9b2e054a3fbc6 [file] [log] [blame]
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +00001// 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
5#include "media/midi/midi_manager.h"
6
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +00007#include <vector>
8
toyoshimc9f52132014-10-15 05:50:07 -07009#include "base/bind.h"
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000010#include "base/logging.h"
11#include "base/memory/scoped_ptr.h"
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +000012#include "base/memory/scoped_vector.h"
toyoshimc9f52132014-10-15 05:50:07 -070013#include "base/message_loop/message_loop.h"
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000014#include "base/run_loop.h"
toyoshim71818732015-04-07 04:15:44 -070015#include "base/system_monitor/system_monitor.h"
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000016#include "testing/gtest/include/gtest/gtest.h"
17
18namespace media {
toyoshime147c5e2015-05-07 21:58:31 -070019namespace midi {
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000020
21namespace {
22
23class FakeMidiManager : public MidiManager {
24 public:
toyoshim7a809662015-10-06 00:54:21 -070025 FakeMidiManager()
26 : start_initialization_is_called_(false), finalize_is_called_(false) {}
dcheng63ccbc32014-10-21 05:23:27 -070027 ~FakeMidiManager() override {}
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000028
29 // MidiManager implementation.
dcheng63ccbc32014-10-21 05:23:27 -070030 void StartInitialization() override {
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000031 start_initialization_is_called_ = true;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000032 }
33
toyoshim7a809662015-10-06 00:54:21 -070034 void Finalize() override { finalize_is_called_ = true; }
35
dcheng63ccbc32014-10-21 05:23:27 -070036 void DispatchSendMidiData(MidiManagerClient* client,
Avi Drissman3528fd02015-12-18 20:11:31 -050037 uint32_t port_index,
38 const std::vector<uint8_t>& data,
dcheng63ccbc32014-10-21 05:23:27 -070039 double timestamp) override {}
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000040
41 // Utility functions for testing.
toyoshimf1b88962015-07-09 14:14:51 -070042 void CallCompleteInitialization(Result result) {
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000043 CompleteInitialization(result);
44 }
45
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000046 size_t GetClientCount() const {
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +000047 return clients_size_for_testing();
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000048 }
49
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000050 size_t GetPendingClientCount() const {
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +000051 return pending_clients_size_for_testing();
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000052 }
53
54 bool start_initialization_is_called_;
toyoshim7a809662015-10-06 00:54:21 -070055 bool finalize_is_called_;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000056
57 private:
58 DISALLOW_COPY_AND_ASSIGN(FakeMidiManager);
59};
60
61class FakeMidiManagerClient : public MidiManagerClient {
62 public:
toyoshima485ff92014-10-23 00:17:59 -070063 FakeMidiManagerClient()
toyoshimf1b88962015-07-09 14:14:51 -070064 : result_(Result::NOT_SUPPORTED), wait_for_result_(true) {}
dcheng63ccbc32014-10-21 05:23:27 -070065 ~FakeMidiManagerClient() override {}
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000066
67 // MidiManagerClient implementation.
toyoshima62d6742014-10-23 09:05:03 -070068 void AddInputPort(const MidiPortInfo& info) override {}
69 void AddOutputPort(const MidiPortInfo& info) override {}
Avi Drissman3528fd02015-12-18 20:11:31 -050070 void SetInputPortState(uint32_t port_index, MidiPortState state) override {}
71 void SetOutputPortState(uint32_t port_index, MidiPortState state) override {}
toyoshima62d6742014-10-23 09:05:03 -070072
toyoshimf1b88962015-07-09 14:14:51 -070073 void CompleteStartSession(Result result) override {
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +000074 EXPECT_TRUE(wait_for_result_);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000075 result_ = result;
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000076 wait_for_result_ = false;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000077 }
78
Avi Drissman3528fd02015-12-18 20:11:31 -050079 void ReceiveMidiData(uint32_t port_index,
80 const uint8_t* data,
dcheng63ccbc32014-10-21 05:23:27 -070081 size_t size,
82 double timestamp) override {}
83 void AccumulateMidiBytesSent(size_t size) override {}
toyoshim7a809662015-10-06 00:54:21 -070084 void Detach() override {}
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000085
toyoshimf1b88962015-07-09 14:14:51 -070086 Result result() const { return result_; }
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000087
toyoshimf1b88962015-07-09 14:14:51 -070088 Result WaitForResult() {
toyoshim11f7d572014-10-20 02:37:10 -070089 while (wait_for_result_) {
90 base::RunLoop run_loop;
91 run_loop.RunUntilIdle();
92 }
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +000093 return result();
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000094 }
95
96 private:
toyoshimf1b88962015-07-09 14:14:51 -070097 Result result_;
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000098 bool wait_for_result_;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000099
100 DISALLOW_COPY_AND_ASSIGN(FakeMidiManagerClient);
101};
102
103class MidiManagerTest : public ::testing::Test {
104 public:
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000105 MidiManagerTest()
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000106 : manager_(new FakeMidiManager),
107 message_loop_(new base::MessageLoop) {}
toyoshim7a809662015-10-06 00:54:21 -0700108 ~MidiManagerTest() override {
109 manager_->Shutdown();
110 base::RunLoop run_loop;
111 run_loop.RunUntilIdle();
112 EXPECT_EQ(manager_->start_initialization_is_called_,
113 manager_->finalize_is_called_);
114 }
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000115
116 protected:
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000117 void StartTheFirstSession(FakeMidiManagerClient* client) {
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000118 EXPECT_FALSE(manager_->start_initialization_is_called_);
119 EXPECT_EQ(0U, manager_->GetClientCount());
120 EXPECT_EQ(0U, manager_->GetPendingClientCount());
toyoshima485ff92014-10-23 00:17:59 -0700121 manager_->StartSession(client);
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000122 EXPECT_EQ(0U, manager_->GetClientCount());
123 EXPECT_EQ(1U, manager_->GetPendingClientCount());
124 EXPECT_TRUE(manager_->start_initialization_is_called_);
125 EXPECT_EQ(0U, manager_->GetClientCount());
126 EXPECT_EQ(1U, manager_->GetPendingClientCount());
127 EXPECT_TRUE(manager_->start_initialization_is_called_);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000128 }
129
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000130 void StartTheNthSession(FakeMidiManagerClient* client, size_t nth) {
131 EXPECT_EQ(nth != 1, manager_->start_initialization_is_called_);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000132 EXPECT_EQ(0U, manager_->GetClientCount());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000133 EXPECT_EQ(nth - 1, manager_->GetPendingClientCount());
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000134
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000135 // StartInitialization() should not be called for the second and later
136 // sessions.
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000137 manager_->start_initialization_is_called_ = false;
toyoshima485ff92014-10-23 00:17:59 -0700138 manager_->StartSession(client);
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000139 EXPECT_EQ(nth == 1, manager_->start_initialization_is_called_);
140 manager_->start_initialization_is_called_ = true;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000141 }
142
143 void EndSession(FakeMidiManagerClient* client, size_t before, size_t after) {
144 EXPECT_EQ(before, manager_->GetClientCount());
145 manager_->EndSession(client);
146 EXPECT_EQ(after, manager_->GetClientCount());
147 }
148
toyoshimf1b88962015-07-09 14:14:51 -0700149 void CompleteInitialization(Result result) {
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000150 manager_->CallCompleteInitialization(result);
151 }
152
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000153 void RunLoopUntilIdle() {
154 base::RunLoop run_loop;
155 run_loop.RunUntilIdle();
156 }
157
158 protected:
159 scoped_ptr<FakeMidiManager> manager_;
160
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000161 private:
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000162 scoped_ptr<base::MessageLoop> message_loop_;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000163
164 DISALLOW_COPY_AND_ASSIGN(MidiManagerTest);
165};
166
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000167TEST_F(MidiManagerTest, StartAndEndSession) {
168 scoped_ptr<FakeMidiManagerClient> client;
toyoshima485ff92014-10-23 00:17:59 -0700169 client.reset(new FakeMidiManagerClient);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000170
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000171 StartTheFirstSession(client.get());
toyoshimf1b88962015-07-09 14:14:51 -0700172 CompleteInitialization(Result::OK);
173 EXPECT_EQ(Result::OK, client->WaitForResult());
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000174 EndSession(client.get(), 1U, 0U);
175}
176
177TEST_F(MidiManagerTest, StartAndEndSessionWithError) {
178 scoped_ptr<FakeMidiManagerClient> client;
toyoshima485ff92014-10-23 00:17:59 -0700179 client.reset(new FakeMidiManagerClient);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000180
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000181 StartTheFirstSession(client.get());
toyoshimf1b88962015-07-09 14:14:51 -0700182 CompleteInitialization(Result::INITIALIZATION_ERROR);
183 EXPECT_EQ(Result::INITIALIZATION_ERROR, client->WaitForResult());
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000184 EndSession(client.get(), 0U, 0U);
185}
186
187TEST_F(MidiManagerTest, StartMultipleSessions) {
188 scoped_ptr<FakeMidiManagerClient> client1;
189 scoped_ptr<FakeMidiManagerClient> client2;
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000190 scoped_ptr<FakeMidiManagerClient> client3;
toyoshima485ff92014-10-23 00:17:59 -0700191 client1.reset(new FakeMidiManagerClient);
192 client2.reset(new FakeMidiManagerClient);
193 client3.reset(new FakeMidiManagerClient);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000194
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000195 StartTheFirstSession(client1.get());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000196 StartTheNthSession(client2.get(), 2);
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000197 StartTheNthSession(client3.get(), 3);
toyoshimf1b88962015-07-09 14:14:51 -0700198 CompleteInitialization(Result::OK);
199 EXPECT_EQ(Result::OK, client1->WaitForResult());
200 EXPECT_EQ(Result::OK, client2->WaitForResult());
201 EXPECT_EQ(Result::OK, client3->WaitForResult());
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000202 EndSession(client1.get(), 3U, 2U);
203 EndSession(client2.get(), 2U, 1U);
204 EndSession(client3.get(), 1U, 0U);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000205}
206
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000207// TODO(toyoshim): Add a test for a MidiManagerClient that has multiple
208// sessions with multiple client_id.
209
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000210TEST_F(MidiManagerTest, TooManyPendingSessions) {
211 // Push as many client requests for starting session as possible.
212 ScopedVector<FakeMidiManagerClient> many_existing_clients;
213 many_existing_clients.resize(MidiManager::kMaxPendingClientCount);
214 for (size_t i = 0; i < MidiManager::kMaxPendingClientCount; ++i) {
toyoshima485ff92014-10-23 00:17:59 -0700215 many_existing_clients[i] = new FakeMidiManagerClient;
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000216 StartTheNthSession(many_existing_clients[i], i + 1);
217 }
toyoshim7a809662015-10-06 00:54:21 -0700218 EXPECT_TRUE(manager_->start_initialization_is_called_);
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000219
220 // Push the last client that should be rejected for too many pending requests.
221 scoped_ptr<FakeMidiManagerClient> additional_client(
toyoshima485ff92014-10-23 00:17:59 -0700222 new FakeMidiManagerClient);
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000223 manager_->start_initialization_is_called_ = false;
toyoshima485ff92014-10-23 00:17:59 -0700224 manager_->StartSession(additional_client.get());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000225 EXPECT_FALSE(manager_->start_initialization_is_called_);
toyoshim7a809662015-10-06 00:54:21 -0700226 manager_->start_initialization_is_called_ = true;
toyoshimf1b88962015-07-09 14:14:51 -0700227 EXPECT_EQ(Result::INITIALIZATION_ERROR, additional_client->result());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000228
229 // Other clients still should not receive a result.
230 RunLoopUntilIdle();
231 for (size_t i = 0; i < many_existing_clients.size(); ++i)
toyoshimf1b88962015-07-09 14:14:51 -0700232 EXPECT_EQ(Result::NOT_SUPPORTED, many_existing_clients[i]->result());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000233
toyoshimf1b88962015-07-09 14:14:51 -0700234 // The Result::OK should be distributed to other clients.
235 CompleteInitialization(Result::OK);
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000236 for (size_t i = 0; i < many_existing_clients.size(); ++i)
toyoshimf1b88962015-07-09 14:14:51 -0700237 EXPECT_EQ(Result::OK, many_existing_clients[i]->WaitForResult());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000238
239 // Close all successful sessions in FIFO order.
240 size_t sessions = many_existing_clients.size();
241 for (size_t i = 0; i < many_existing_clients.size(); ++i, --sessions)
242 EndSession(many_existing_clients[i], sessions, sessions - 1);
243}
244
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000245TEST_F(MidiManagerTest, AbortSession) {
246 // A client starting a session can be destructed while an asynchronous
247 // initialization is performed.
248 scoped_ptr<FakeMidiManagerClient> client;
toyoshima485ff92014-10-23 00:17:59 -0700249 client.reset(new FakeMidiManagerClient);
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000250
251 StartTheFirstSession(client.get());
252 EndSession(client.get(), 0, 0);
253 client.reset();
254
255 // Following function should not call the destructed |client| function.
toyoshimf1b88962015-07-09 14:14:51 -0700256 CompleteInitialization(Result::OK);
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000257 base::RunLoop run_loop;
258 run_loop.RunUntilIdle();
259}
260
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000261TEST_F(MidiManagerTest, CreateMidiManager) {
toyoshim71818732015-04-07 04:15:44 -0700262 // SystemMonitor is needed on Windows.
263 base::SystemMonitor system_monitor;
264
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000265 scoped_ptr<FakeMidiManagerClient> client;
toyoshima485ff92014-10-23 00:17:59 -0700266 client.reset(new FakeMidiManagerClient);
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000267
268 scoped_ptr<MidiManager> manager(MidiManager::Create());
toyoshima485ff92014-10-23 00:17:59 -0700269 manager->StartSession(client.get());
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +0000270
toyoshimf1b88962015-07-09 14:14:51 -0700271 Result result = client->WaitForResult();
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +0000272 // This #ifdef needs to be identical to the one in media/midi/midi_manager.cc.
273 // Do not change the condition for disabling this test.
agoode7de413f2015-04-24 00:13:39 -0700274#if !defined(OS_MACOSX) && !defined(OS_WIN) && \
275 !(defined(USE_ALSA) && defined(USE_UDEV)) && !defined(OS_ANDROID)
toyoshimf1b88962015-07-09 14:14:51 -0700276 EXPECT_EQ(Result::NOT_SUPPORTED, result);
agoode@chromium.org25227512014-06-08 05:12:05 +0000277#elif defined(USE_ALSA)
278 // Temporary until http://crbug.com/371230 is resolved.
toyoshimf1b88962015-07-09 14:14:51 -0700279 EXPECT_TRUE(result == Result::OK || result == Result::INITIALIZATION_ERROR);
dnicoara@chromium.orgc404df62014-05-06 22:56:00 +0000280#else
toyoshimf1b88962015-07-09 14:14:51 -0700281 EXPECT_EQ(Result::OK, result);
dnicoara@chromium.orgc404df62014-05-06 22:56:00 +0000282#endif
toyoshim7a809662015-10-06 00:54:21 -0700283
284 manager->Shutdown();
285 base::RunLoop run_loop;
286 run_loop.RunUntilIdle();
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000287}
288
toyoshim7a809662015-10-06 00:54:21 -0700289// TODO(toyoshim): Add multi-threaded unit tests to check races around
290// StartInitialization(), CompleteInitialization(), and Finalize().
291
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000292} // namespace
293
toyoshime147c5e2015-05-07 21:58:31 -0700294} // namespace midi
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000295} // namespace media