blob: ffbcd0fdab44b7eaed6712438f3a4bb974aa168b [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 {
19
20namespace {
21
22class FakeMidiManager : public MidiManager {
23 public:
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000024 FakeMidiManager() : start_initialization_is_called_(false) {}
dcheng63ccbc32014-10-21 05:23:27 -070025 ~FakeMidiManager() override {}
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000026
27 // MidiManager implementation.
dcheng63ccbc32014-10-21 05:23:27 -070028 void StartInitialization() override {
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000029 start_initialization_is_called_ = true;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000030 }
31
dcheng63ccbc32014-10-21 05:23:27 -070032 void DispatchSendMidiData(MidiManagerClient* client,
33 uint32 port_index,
34 const std::vector<uint8>& data,
35 double timestamp) override {}
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000036
37 // Utility functions for testing.
38 void CallCompleteInitialization(MidiResult result) {
39 CompleteInitialization(result);
40 }
41
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000042 size_t GetClientCount() const {
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +000043 return clients_size_for_testing();
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000044 }
45
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000046 size_t GetPendingClientCount() const {
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +000047 return pending_clients_size_for_testing();
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000048 }
49
50 bool start_initialization_is_called_;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000051
52 private:
53 DISALLOW_COPY_AND_ASSIGN(FakeMidiManager);
54};
55
56class FakeMidiManagerClient : public MidiManagerClient {
57 public:
toyoshima485ff92014-10-23 00:17:59 -070058 FakeMidiManagerClient()
59 : result_(MIDI_NOT_SUPPORTED),
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000060 wait_for_result_(true) {}
dcheng63ccbc32014-10-21 05:23:27 -070061 ~FakeMidiManagerClient() override {}
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000062
63 // MidiManagerClient implementation.
toyoshima62d6742014-10-23 09:05:03 -070064 void AddInputPort(const MidiPortInfo& info) override {}
65 void AddOutputPort(const MidiPortInfo& info) override {}
toyoshim5c6fe4b2015-02-18 23:28:09 -080066 void SetInputPortState(uint32 port_index, MidiPortState state) override {}
67 void SetOutputPortState(uint32 port_index, MidiPortState state) override {}
toyoshima62d6742014-10-23 09:05:03 -070068
toyoshima485ff92014-10-23 00:17:59 -070069 void CompleteStartSession(MidiResult result) override {
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +000070 EXPECT_TRUE(wait_for_result_);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000071 result_ = result;
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000072 wait_for_result_ = false;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000073 }
74
dcheng63ccbc32014-10-21 05:23:27 -070075 void ReceiveMidiData(uint32 port_index,
76 const uint8* data,
77 size_t size,
78 double timestamp) override {}
79 void AccumulateMidiBytesSent(size_t size) override {}
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000080
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +000081 MidiResult result() const { return result_; }
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000082
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000083 MidiResult WaitForResult() {
toyoshim11f7d572014-10-20 02:37:10 -070084 while (wait_for_result_) {
85 base::RunLoop run_loop;
86 run_loop.RunUntilIdle();
87 }
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +000088 return result();
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000089 }
90
91 private:
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000092 MidiResult result_;
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000093 bool wait_for_result_;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000094
95 DISALLOW_COPY_AND_ASSIGN(FakeMidiManagerClient);
96};
97
98class MidiManagerTest : public ::testing::Test {
99 public:
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000100 MidiManagerTest()
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000101 : manager_(new FakeMidiManager),
102 message_loop_(new base::MessageLoop) {}
dcheng9e8524d2014-10-27 15:18:50 -0700103 ~MidiManagerTest() override {}
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000104
105 protected:
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000106 void StartTheFirstSession(FakeMidiManagerClient* client) {
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000107 EXPECT_FALSE(manager_->start_initialization_is_called_);
108 EXPECT_EQ(0U, manager_->GetClientCount());
109 EXPECT_EQ(0U, manager_->GetPendingClientCount());
toyoshima485ff92014-10-23 00:17:59 -0700110 manager_->StartSession(client);
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000111 EXPECT_EQ(0U, manager_->GetClientCount());
112 EXPECT_EQ(1U, manager_->GetPendingClientCount());
113 EXPECT_TRUE(manager_->start_initialization_is_called_);
114 EXPECT_EQ(0U, manager_->GetClientCount());
115 EXPECT_EQ(1U, manager_->GetPendingClientCount());
116 EXPECT_TRUE(manager_->start_initialization_is_called_);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000117 }
118
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000119 void StartTheNthSession(FakeMidiManagerClient* client, size_t nth) {
120 EXPECT_EQ(nth != 1, manager_->start_initialization_is_called_);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000121 EXPECT_EQ(0U, manager_->GetClientCount());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000122 EXPECT_EQ(nth - 1, manager_->GetPendingClientCount());
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000123
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000124 // StartInitialization() should not be called for the second and later
125 // sessions.
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000126 manager_->start_initialization_is_called_ = false;
toyoshima485ff92014-10-23 00:17:59 -0700127 manager_->StartSession(client);
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000128 EXPECT_EQ(nth == 1, manager_->start_initialization_is_called_);
129 manager_->start_initialization_is_called_ = true;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000130 }
131
132 void EndSession(FakeMidiManagerClient* client, size_t before, size_t after) {
133 EXPECT_EQ(before, manager_->GetClientCount());
134 manager_->EndSession(client);
135 EXPECT_EQ(after, manager_->GetClientCount());
136 }
137
138 void CompleteInitialization(MidiResult result) {
139 manager_->CallCompleteInitialization(result);
140 }
141
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000142 void RunLoopUntilIdle() {
143 base::RunLoop run_loop;
144 run_loop.RunUntilIdle();
145 }
146
147 protected:
148 scoped_ptr<FakeMidiManager> manager_;
149
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000150 private:
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000151 scoped_ptr<base::MessageLoop> message_loop_;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000152
153 DISALLOW_COPY_AND_ASSIGN(MidiManagerTest);
154};
155
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000156TEST_F(MidiManagerTest, StartAndEndSession) {
157 scoped_ptr<FakeMidiManagerClient> client;
toyoshima485ff92014-10-23 00:17:59 -0700158 client.reset(new FakeMidiManagerClient);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000159
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000160 StartTheFirstSession(client.get());
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000161 CompleteInitialization(MIDI_OK);
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000162 EXPECT_EQ(MIDI_OK, client->WaitForResult());
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000163 EndSession(client.get(), 1U, 0U);
164}
165
166TEST_F(MidiManagerTest, StartAndEndSessionWithError) {
167 scoped_ptr<FakeMidiManagerClient> client;
toyoshima485ff92014-10-23 00:17:59 -0700168 client.reset(new FakeMidiManagerClient);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000169
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000170 StartTheFirstSession(client.get());
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000171 CompleteInitialization(MIDI_INITIALIZATION_ERROR);
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000172 EXPECT_EQ(MIDI_INITIALIZATION_ERROR, client->WaitForResult());
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000173 EndSession(client.get(), 0U, 0U);
174}
175
176TEST_F(MidiManagerTest, StartMultipleSessions) {
177 scoped_ptr<FakeMidiManagerClient> client1;
178 scoped_ptr<FakeMidiManagerClient> client2;
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000179 scoped_ptr<FakeMidiManagerClient> client3;
toyoshima485ff92014-10-23 00:17:59 -0700180 client1.reset(new FakeMidiManagerClient);
181 client2.reset(new FakeMidiManagerClient);
182 client3.reset(new FakeMidiManagerClient);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000183
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000184 StartTheFirstSession(client1.get());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000185 StartTheNthSession(client2.get(), 2);
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000186 StartTheNthSession(client3.get(), 3);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000187 CompleteInitialization(MIDI_OK);
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000188 EXPECT_EQ(MIDI_OK, client1->WaitForResult());
189 EXPECT_EQ(MIDI_OK, client2->WaitForResult());
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000190 EXPECT_EQ(MIDI_OK, client3->WaitForResult());
191 EndSession(client1.get(), 3U, 2U);
192 EndSession(client2.get(), 2U, 1U);
193 EndSession(client3.get(), 1U, 0U);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000194}
195
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000196// TODO(toyoshim): Add a test for a MidiManagerClient that has multiple
197// sessions with multiple client_id.
198
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000199TEST_F(MidiManagerTest, TooManyPendingSessions) {
200 // Push as many client requests for starting session as possible.
201 ScopedVector<FakeMidiManagerClient> many_existing_clients;
202 many_existing_clients.resize(MidiManager::kMaxPendingClientCount);
203 for (size_t i = 0; i < MidiManager::kMaxPendingClientCount; ++i) {
toyoshima485ff92014-10-23 00:17:59 -0700204 many_existing_clients[i] = new FakeMidiManagerClient;
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000205 StartTheNthSession(many_existing_clients[i], i + 1);
206 }
207
208 // Push the last client that should be rejected for too many pending requests.
209 scoped_ptr<FakeMidiManagerClient> additional_client(
toyoshima485ff92014-10-23 00:17:59 -0700210 new FakeMidiManagerClient);
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000211 manager_->start_initialization_is_called_ = false;
toyoshima485ff92014-10-23 00:17:59 -0700212 manager_->StartSession(additional_client.get());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000213 EXPECT_FALSE(manager_->start_initialization_is_called_);
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +0000214 EXPECT_EQ(MIDI_INITIALIZATION_ERROR, additional_client->result());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000215
216 // Other clients still should not receive a result.
217 RunLoopUntilIdle();
218 for (size_t i = 0; i < many_existing_clients.size(); ++i)
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +0000219 EXPECT_EQ(MIDI_NOT_SUPPORTED, many_existing_clients[i]->result());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000220
221 // The result MIDI_OK should be distributed to other clients.
222 CompleteInitialization(MIDI_OK);
223 for (size_t i = 0; i < many_existing_clients.size(); ++i)
224 EXPECT_EQ(MIDI_OK, many_existing_clients[i]->WaitForResult());
225
226 // Close all successful sessions in FIFO order.
227 size_t sessions = many_existing_clients.size();
228 for (size_t i = 0; i < many_existing_clients.size(); ++i, --sessions)
229 EndSession(many_existing_clients[i], sessions, sessions - 1);
230}
231
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000232TEST_F(MidiManagerTest, AbortSession) {
233 // A client starting a session can be destructed while an asynchronous
234 // initialization is performed.
235 scoped_ptr<FakeMidiManagerClient> client;
toyoshima485ff92014-10-23 00:17:59 -0700236 client.reset(new FakeMidiManagerClient);
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000237
238 StartTheFirstSession(client.get());
239 EndSession(client.get(), 0, 0);
240 client.reset();
241
242 // Following function should not call the destructed |client| function.
243 CompleteInitialization(MIDI_OK);
244 base::RunLoop run_loop;
245 run_loop.RunUntilIdle();
246}
247
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000248TEST_F(MidiManagerTest, CreateMidiManager) {
toyoshim71818732015-04-07 04:15:44 -0700249 // SystemMonitor is needed on Windows.
250 base::SystemMonitor system_monitor;
251
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000252 scoped_ptr<FakeMidiManagerClient> client;
toyoshima485ff92014-10-23 00:17:59 -0700253 client.reset(new FakeMidiManagerClient);
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000254
255 scoped_ptr<MidiManager> manager(MidiManager::Create());
toyoshima485ff92014-10-23 00:17:59 -0700256 manager->StartSession(client.get());
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +0000257
agoode@chromium.org25227512014-06-08 05:12:05 +0000258 MidiResult result = client->WaitForResult();
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +0000259 // This #ifdef needs to be identical to the one in media/midi/midi_manager.cc.
260 // Do not change the condition for disabling this test.
dnicoara@chromium.orgc404df62014-05-06 22:56:00 +0000261#if !defined(OS_MACOSX) && !defined(OS_WIN) && !defined(USE_ALSA) && \
262 !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
agoode@chromium.org25227512014-06-08 05:12:05 +0000263 EXPECT_EQ(MIDI_NOT_SUPPORTED, result);
264#elif defined(USE_ALSA)
265 // Temporary until http://crbug.com/371230 is resolved.
266 EXPECT_TRUE((result == MIDI_OK) || (result == MIDI_INITIALIZATION_ERROR));
dnicoara@chromium.orgc404df62014-05-06 22:56:00 +0000267#else
agoode@chromium.org25227512014-06-08 05:12:05 +0000268 EXPECT_EQ(MIDI_OK, result);
dnicoara@chromium.orgc404df62014-05-06 22:56:00 +0000269#endif
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000270}
271
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000272} // namespace
273
274} // namespace media