blob: 5782b725ada5731298504e03d3f0bbaddaf4804f [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"
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000015#include "testing/gtest/include/gtest/gtest.h"
16
17namespace media {
18
19namespace {
20
21class FakeMidiManager : public MidiManager {
22 public:
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000023 FakeMidiManager() : start_initialization_is_called_(false) {}
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000024 virtual ~FakeMidiManager() {}
25
26 // MidiManager implementation.
mostynb64fb4dc2014-10-06 18:04:44 -070027 virtual void StartInitialization() override {
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000028 start_initialization_is_called_ = true;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000029 }
30
31 virtual void DispatchSendMidiData(MidiManagerClient* client,
32 uint32 port_index,
33 const std::vector<uint8>& data,
mostynb64fb4dc2014-10-06 18:04:44 -070034 double timestamp) override {}
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000035
36 // Utility functions for testing.
37 void CallCompleteInitialization(MidiResult result) {
38 CompleteInitialization(result);
39 }
40
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000041 size_t GetClientCount() const {
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +000042 return clients_size_for_testing();
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000043 }
44
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000045 size_t GetPendingClientCount() const {
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +000046 return pending_clients_size_for_testing();
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000047 }
48
49 bool start_initialization_is_called_;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000050
51 private:
52 DISALLOW_COPY_AND_ASSIGN(FakeMidiManager);
53};
54
55class FakeMidiManagerClient : public MidiManagerClient {
56 public:
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000057 explicit FakeMidiManagerClient(int client_id)
58 : client_id_(client_id),
59 result_(MIDI_NOT_SUPPORTED),
60 wait_for_result_(true) {}
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000061 virtual ~FakeMidiManagerClient() {}
62
63 // MidiManagerClient implementation.
mostynb64fb4dc2014-10-06 18:04:44 -070064 virtual void CompleteStartSession(int client_id, MidiResult result) override {
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +000065 EXPECT_TRUE(wait_for_result_);
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000066 CHECK_EQ(client_id_, client_id);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000067 result_ = result;
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000068 wait_for_result_ = false;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000069 }
70
71 virtual void ReceiveMidiData(uint32 port_index, const uint8* data,
mostynb64fb4dc2014-10-06 18:04:44 -070072 size_t size, double timestamp) override {}
73 virtual void AccumulateMidiBytesSent(size_t size) override {}
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000074
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +000075 int client_id() const { return client_id_; }
76 MidiResult result() const { return result_; }
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000077
toyoshimc9f52132014-10-15 05:50:07 -070078 void HandleContinuationMessage() {
79 // Stop posting a dummy message once CompleteStartSession() is invoked.
80 if (!wait_for_result_)
81 return;
82 base::MessageLoop::current()->PostTask(
83 FROM_HERE,
84 base::Bind(&FakeMidiManagerClient::HandleContinuationMessage,
85 base::Unretained(this)));
86 }
87
88
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000089 MidiResult WaitForResult() {
90 base::RunLoop run_loop;
toyoshimc9f52132014-10-15 05:50:07 -070091 // Post a dummy task not to stop the following event loop.
92 HandleContinuationMessage();
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000093 // CompleteStartSession() is called inside the message loop on the same
94 // thread. Protection for |wait_for_result_| is not needed.
toyoshimc9f52132014-10-15 05:50:07 -070095 run_loop.RunUntilIdle();
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +000096 return result();
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000097 }
98
99 private:
100 int client_id_;
101 MidiResult result_;
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000102 bool wait_for_result_;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000103
104 DISALLOW_COPY_AND_ASSIGN(FakeMidiManagerClient);
105};
106
107class MidiManagerTest : public ::testing::Test {
108 public:
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000109 MidiManagerTest()
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000110 : manager_(new FakeMidiManager),
111 message_loop_(new base::MessageLoop) {}
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000112 virtual ~MidiManagerTest() {}
113
114 protected:
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000115 void StartTheFirstSession(FakeMidiManagerClient* client) {
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000116 EXPECT_FALSE(manager_->start_initialization_is_called_);
117 EXPECT_EQ(0U, manager_->GetClientCount());
118 EXPECT_EQ(0U, manager_->GetPendingClientCount());
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +0000119 manager_->StartSession(client, client->client_id());
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000120 EXPECT_EQ(0U, manager_->GetClientCount());
121 EXPECT_EQ(1U, manager_->GetPendingClientCount());
122 EXPECT_TRUE(manager_->start_initialization_is_called_);
123 EXPECT_EQ(0U, manager_->GetClientCount());
124 EXPECT_EQ(1U, manager_->GetPendingClientCount());
125 EXPECT_TRUE(manager_->start_initialization_is_called_);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000126 }
127
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000128 void StartTheNthSession(FakeMidiManagerClient* client, size_t nth) {
129 EXPECT_EQ(nth != 1, manager_->start_initialization_is_called_);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000130 EXPECT_EQ(0U, manager_->GetClientCount());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000131 EXPECT_EQ(nth - 1, manager_->GetPendingClientCount());
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000132
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000133 // StartInitialization() should not be called for the second and later
134 // sessions.
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000135 manager_->start_initialization_is_called_ = false;
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +0000136 manager_->StartSession(client, client->client_id());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000137 EXPECT_EQ(nth == 1, manager_->start_initialization_is_called_);
138 manager_->start_initialization_is_called_ = true;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000139 }
140
141 void EndSession(FakeMidiManagerClient* client, size_t before, size_t after) {
142 EXPECT_EQ(before, manager_->GetClientCount());
143 manager_->EndSession(client);
144 EXPECT_EQ(after, manager_->GetClientCount());
145 }
146
147 void CompleteInitialization(MidiResult result) {
148 manager_->CallCompleteInitialization(result);
149 }
150
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000151 void RunLoopUntilIdle() {
152 base::RunLoop run_loop;
153 run_loop.RunUntilIdle();
154 }
155
156 protected:
157 scoped_ptr<FakeMidiManager> manager_;
158
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000159 private:
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000160 scoped_ptr<base::MessageLoop> message_loop_;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000161
162 DISALLOW_COPY_AND_ASSIGN(MidiManagerTest);
163};
164
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000165TEST_F(MidiManagerTest, StartAndEndSession) {
166 scoped_ptr<FakeMidiManagerClient> client;
167 client.reset(new FakeMidiManagerClient(0));
168
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000169 StartTheFirstSession(client.get());
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000170 CompleteInitialization(MIDI_OK);
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000171 EXPECT_EQ(MIDI_OK, client->WaitForResult());
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000172 EndSession(client.get(), 1U, 0U);
173}
174
175TEST_F(MidiManagerTest, StartAndEndSessionWithError) {
176 scoped_ptr<FakeMidiManagerClient> client;
177 client.reset(new FakeMidiManagerClient(1));
178
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000179 StartTheFirstSession(client.get());
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000180 CompleteInitialization(MIDI_INITIALIZATION_ERROR);
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000181 EXPECT_EQ(MIDI_INITIALIZATION_ERROR, client->WaitForResult());
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000182 EndSession(client.get(), 0U, 0U);
183}
184
185TEST_F(MidiManagerTest, StartMultipleSessions) {
186 scoped_ptr<FakeMidiManagerClient> client1;
187 scoped_ptr<FakeMidiManagerClient> client2;
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000188 scoped_ptr<FakeMidiManagerClient> client3;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000189 client1.reset(new FakeMidiManagerClient(0));
190 client2.reset(new FakeMidiManagerClient(1));
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000191 client3.reset(new FakeMidiManagerClient(1));
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000192
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000193 StartTheFirstSession(client1.get());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000194 StartTheNthSession(client2.get(), 2);
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000195 StartTheNthSession(client3.get(), 3);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000196 CompleteInitialization(MIDI_OK);
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000197 EXPECT_EQ(MIDI_OK, client1->WaitForResult());
198 EXPECT_EQ(MIDI_OK, client2->WaitForResult());
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000199 EXPECT_EQ(MIDI_OK, client3->WaitForResult());
200 EndSession(client1.get(), 3U, 2U);
201 EndSession(client2.get(), 2U, 1U);
202 EndSession(client3.get(), 1U, 0U);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000203}
204
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000205// TODO(toyoshim): Add a test for a MidiManagerClient that has multiple
206// sessions with multiple client_id.
207
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000208TEST_F(MidiManagerTest, TooManyPendingSessions) {
209 // Push as many client requests for starting session as possible.
210 ScopedVector<FakeMidiManagerClient> many_existing_clients;
211 many_existing_clients.resize(MidiManager::kMaxPendingClientCount);
212 for (size_t i = 0; i < MidiManager::kMaxPendingClientCount; ++i) {
213 many_existing_clients[i] = new FakeMidiManagerClient(i);
214 StartTheNthSession(many_existing_clients[i], i + 1);
215 }
216
217 // Push the last client that should be rejected for too many pending requests.
218 scoped_ptr<FakeMidiManagerClient> additional_client(
219 new FakeMidiManagerClient(MidiManager::kMaxPendingClientCount));
220 manager_->start_initialization_is_called_ = false;
221 manager_->StartSession(additional_client.get(),
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +0000222 additional_client->client_id());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000223 EXPECT_FALSE(manager_->start_initialization_is_called_);
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +0000224 EXPECT_EQ(MIDI_INITIALIZATION_ERROR, additional_client->result());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000225
226 // Other clients still should not receive a result.
227 RunLoopUntilIdle();
228 for (size_t i = 0; i < many_existing_clients.size(); ++i)
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +0000229 EXPECT_EQ(MIDI_NOT_SUPPORTED, many_existing_clients[i]->result());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000230
231 // The result MIDI_OK should be distributed to other clients.
232 CompleteInitialization(MIDI_OK);
233 for (size_t i = 0; i < many_existing_clients.size(); ++i)
234 EXPECT_EQ(MIDI_OK, many_existing_clients[i]->WaitForResult());
235
236 // Close all successful sessions in FIFO order.
237 size_t sessions = many_existing_clients.size();
238 for (size_t i = 0; i < many_existing_clients.size(); ++i, --sessions)
239 EndSession(many_existing_clients[i], sessions, sessions - 1);
240}
241
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000242TEST_F(MidiManagerTest, AbortSession) {
243 // A client starting a session can be destructed while an asynchronous
244 // initialization is performed.
245 scoped_ptr<FakeMidiManagerClient> client;
246 client.reset(new FakeMidiManagerClient(0));
247
248 StartTheFirstSession(client.get());
249 EndSession(client.get(), 0, 0);
250 client.reset();
251
252 // Following function should not call the destructed |client| function.
253 CompleteInitialization(MIDI_OK);
254 base::RunLoop run_loop;
255 run_loop.RunUntilIdle();
256}
257
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000258TEST_F(MidiManagerTest, CreateMidiManager) {
259 scoped_ptr<FakeMidiManagerClient> client;
260 client.reset(new FakeMidiManagerClient(0));
261
262 scoped_ptr<MidiManager> manager(MidiManager::Create());
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +0000263 manager->StartSession(client.get(), client->client_id());
264
agoode@chromium.org25227512014-06-08 05:12:05 +0000265 MidiResult result = client->WaitForResult();
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +0000266 // This #ifdef needs to be identical to the one in media/midi/midi_manager.cc.
267 // Do not change the condition for disabling this test.
dnicoara@chromium.orgc404df62014-05-06 22:56:00 +0000268#if !defined(OS_MACOSX) && !defined(OS_WIN) && !defined(USE_ALSA) && \
269 !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
agoode@chromium.org25227512014-06-08 05:12:05 +0000270 EXPECT_EQ(MIDI_NOT_SUPPORTED, result);
271#elif defined(USE_ALSA)
272 // Temporary until http://crbug.com/371230 is resolved.
273 EXPECT_TRUE((result == MIDI_OK) || (result == MIDI_INITIALIZATION_ERROR));
dnicoara@chromium.orgc404df62014-05-06 22:56:00 +0000274#else
agoode@chromium.org25227512014-06-08 05:12:05 +0000275 EXPECT_EQ(MIDI_OK, result);
dnicoara@chromium.orgc404df62014-05-06 22:56:00 +0000276#endif
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000277}
278
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000279} // namespace
280
281} // namespace media