blob: 2e9127e621e965d7ea4be22147a1982e578e9925 [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
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +00009#include "base/logging.h"
10#include "base/memory/scoped_ptr.h"
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +000011#include "base/memory/scoped_vector.h"
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000012#include "base/run_loop.h"
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000013#include "testing/gtest/include/gtest/gtest.h"
14
15namespace media {
16
17namespace {
18
19class FakeMidiManager : public MidiManager {
20 public:
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000021 FakeMidiManager() : start_initialization_is_called_(false) {}
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000022 virtual ~FakeMidiManager() {}
23
24 // MidiManager implementation.
mostynb64fb4dc2014-10-06 18:04:44 -070025 virtual void StartInitialization() override {
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000026 start_initialization_is_called_ = true;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000027 }
28
29 virtual void DispatchSendMidiData(MidiManagerClient* client,
30 uint32 port_index,
31 const std::vector<uint8>& data,
mostynb64fb4dc2014-10-06 18:04:44 -070032 double timestamp) override {}
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000033
34 // Utility functions for testing.
35 void CallCompleteInitialization(MidiResult result) {
36 CompleteInitialization(result);
37 }
38
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000039 size_t GetClientCount() const {
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +000040 return clients_size_for_testing();
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000041 }
42
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000043 size_t GetPendingClientCount() const {
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +000044 return pending_clients_size_for_testing();
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000045 }
46
47 bool start_initialization_is_called_;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000048
49 private:
50 DISALLOW_COPY_AND_ASSIGN(FakeMidiManager);
51};
52
53class FakeMidiManagerClient : public MidiManagerClient {
54 public:
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000055 explicit FakeMidiManagerClient(int client_id)
56 : client_id_(client_id),
57 result_(MIDI_NOT_SUPPORTED),
58 wait_for_result_(true) {}
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000059 virtual ~FakeMidiManagerClient() {}
60
61 // MidiManagerClient implementation.
mostynb64fb4dc2014-10-06 18:04:44 -070062 virtual void CompleteStartSession(int client_id, MidiResult result) override {
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +000063 EXPECT_TRUE(wait_for_result_);
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000064 CHECK_EQ(client_id_, client_id);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000065 result_ = result;
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000066 wait_for_result_ = false;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000067 }
68
69 virtual void ReceiveMidiData(uint32 port_index, const uint8* data,
mostynb64fb4dc2014-10-06 18:04:44 -070070 size_t size, double timestamp) override {}
71 virtual void AccumulateMidiBytesSent(size_t size) override {}
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000072
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +000073 int client_id() const { return client_id_; }
74 MidiResult result() const { return result_; }
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000075
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000076 MidiResult WaitForResult() {
77 base::RunLoop run_loop;
78 // CompleteStartSession() is called inside the message loop on the same
79 // thread. Protection for |wait_for_result_| is not needed.
80 while (wait_for_result_)
81 run_loop.RunUntilIdle();
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +000082 return result();
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000083 }
84
85 private:
86 int client_id_;
87 MidiResult result_;
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000088 bool wait_for_result_;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000089
90 DISALLOW_COPY_AND_ASSIGN(FakeMidiManagerClient);
91};
92
93class MidiManagerTest : public ::testing::Test {
94 public:
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +000095 MidiManagerTest()
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +000096 : manager_(new FakeMidiManager),
97 message_loop_(new base::MessageLoop) {}
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +000098 virtual ~MidiManagerTest() {}
99
100 protected:
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000101 void StartTheFirstSession(FakeMidiManagerClient* client) {
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000102 EXPECT_FALSE(manager_->start_initialization_is_called_);
103 EXPECT_EQ(0U, manager_->GetClientCount());
104 EXPECT_EQ(0U, manager_->GetPendingClientCount());
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +0000105 manager_->StartSession(client, client->client_id());
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000106 EXPECT_EQ(0U, manager_->GetClientCount());
107 EXPECT_EQ(1U, manager_->GetPendingClientCount());
108 EXPECT_TRUE(manager_->start_initialization_is_called_);
109 EXPECT_EQ(0U, manager_->GetClientCount());
110 EXPECT_EQ(1U, manager_->GetPendingClientCount());
111 EXPECT_TRUE(manager_->start_initialization_is_called_);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000112 }
113
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000114 void StartTheNthSession(FakeMidiManagerClient* client, size_t nth) {
115 EXPECT_EQ(nth != 1, manager_->start_initialization_is_called_);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000116 EXPECT_EQ(0U, manager_->GetClientCount());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000117 EXPECT_EQ(nth - 1, manager_->GetPendingClientCount());
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000118
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000119 // StartInitialization() should not be called for the second and later
120 // sessions.
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000121 manager_->start_initialization_is_called_ = false;
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +0000122 manager_->StartSession(client, client->client_id());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000123 EXPECT_EQ(nth == 1, manager_->start_initialization_is_called_);
124 manager_->start_initialization_is_called_ = true;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000125 }
126
127 void EndSession(FakeMidiManagerClient* client, size_t before, size_t after) {
128 EXPECT_EQ(before, manager_->GetClientCount());
129 manager_->EndSession(client);
130 EXPECT_EQ(after, manager_->GetClientCount());
131 }
132
133 void CompleteInitialization(MidiResult result) {
134 manager_->CallCompleteInitialization(result);
135 }
136
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000137 void RunLoopUntilIdle() {
138 base::RunLoop run_loop;
139 run_loop.RunUntilIdle();
140 }
141
142 protected:
143 scoped_ptr<FakeMidiManager> manager_;
144
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000145 private:
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000146 scoped_ptr<base::MessageLoop> message_loop_;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000147
148 DISALLOW_COPY_AND_ASSIGN(MidiManagerTest);
149};
150
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000151TEST_F(MidiManagerTest, StartAndEndSession) {
152 scoped_ptr<FakeMidiManagerClient> client;
153 client.reset(new FakeMidiManagerClient(0));
154
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000155 StartTheFirstSession(client.get());
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000156 CompleteInitialization(MIDI_OK);
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000157 EXPECT_EQ(MIDI_OK, client->WaitForResult());
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000158 EndSession(client.get(), 1U, 0U);
159}
160
161TEST_F(MidiManagerTest, StartAndEndSessionWithError) {
162 scoped_ptr<FakeMidiManagerClient> client;
163 client.reset(new FakeMidiManagerClient(1));
164
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000165 StartTheFirstSession(client.get());
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000166 CompleteInitialization(MIDI_INITIALIZATION_ERROR);
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000167 EXPECT_EQ(MIDI_INITIALIZATION_ERROR, client->WaitForResult());
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000168 EndSession(client.get(), 0U, 0U);
169}
170
171TEST_F(MidiManagerTest, StartMultipleSessions) {
172 scoped_ptr<FakeMidiManagerClient> client1;
173 scoped_ptr<FakeMidiManagerClient> client2;
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000174 scoped_ptr<FakeMidiManagerClient> client3;
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000175 client1.reset(new FakeMidiManagerClient(0));
176 client2.reset(new FakeMidiManagerClient(1));
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000177 client3.reset(new FakeMidiManagerClient(1));
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000178
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000179 StartTheFirstSession(client1.get());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000180 StartTheNthSession(client2.get(), 2);
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000181 StartTheNthSession(client3.get(), 3);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000182 CompleteInitialization(MIDI_OK);
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000183 EXPECT_EQ(MIDI_OK, client1->WaitForResult());
184 EXPECT_EQ(MIDI_OK, client2->WaitForResult());
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000185 EXPECT_EQ(MIDI_OK, client3->WaitForResult());
186 EndSession(client1.get(), 3U, 2U);
187 EndSession(client2.get(), 2U, 1U);
188 EndSession(client3.get(), 1U, 0U);
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000189}
190
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000191// TODO(toyoshim): Add a test for a MidiManagerClient that has multiple
192// sessions with multiple client_id.
193
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000194TEST_F(MidiManagerTest, TooManyPendingSessions) {
195 // Push as many client requests for starting session as possible.
196 ScopedVector<FakeMidiManagerClient> many_existing_clients;
197 many_existing_clients.resize(MidiManager::kMaxPendingClientCount);
198 for (size_t i = 0; i < MidiManager::kMaxPendingClientCount; ++i) {
199 many_existing_clients[i] = new FakeMidiManagerClient(i);
200 StartTheNthSession(many_existing_clients[i], i + 1);
201 }
202
203 // Push the last client that should be rejected for too many pending requests.
204 scoped_ptr<FakeMidiManagerClient> additional_client(
205 new FakeMidiManagerClient(MidiManager::kMaxPendingClientCount));
206 manager_->start_initialization_is_called_ = false;
207 manager_->StartSession(additional_client.get(),
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +0000208 additional_client->client_id());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000209 EXPECT_FALSE(manager_->start_initialization_is_called_);
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +0000210 EXPECT_EQ(MIDI_INITIALIZATION_ERROR, additional_client->result());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000211
212 // Other clients still should not receive a result.
213 RunLoopUntilIdle();
214 for (size_t i = 0; i < many_existing_clients.size(); ++i)
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +0000215 EXPECT_EQ(MIDI_NOT_SUPPORTED, many_existing_clients[i]->result());
toyoshim@chromium.orgfc2002e2014-05-07 08:10:34 +0000216
217 // The result MIDI_OK should be distributed to other clients.
218 CompleteInitialization(MIDI_OK);
219 for (size_t i = 0; i < many_existing_clients.size(); ++i)
220 EXPECT_EQ(MIDI_OK, many_existing_clients[i]->WaitForResult());
221
222 // Close all successful sessions in FIFO order.
223 size_t sessions = many_existing_clients.size();
224 for (size_t i = 0; i < many_existing_clients.size(); ++i, --sessions)
225 EndSession(many_existing_clients[i], sessions, sessions - 1);
226}
227
toyoshim@chromium.org1fa678a2014-06-13 09:40:33 +0000228TEST_F(MidiManagerTest, AbortSession) {
229 // A client starting a session can be destructed while an asynchronous
230 // initialization is performed.
231 scoped_ptr<FakeMidiManagerClient> client;
232 client.reset(new FakeMidiManagerClient(0));
233
234 StartTheFirstSession(client.get());
235 EndSession(client.get(), 0, 0);
236 client.reset();
237
238 // Following function should not call the destructed |client| function.
239 CompleteInitialization(MIDI_OK);
240 base::RunLoop run_loop;
241 run_loop.RunUntilIdle();
242}
243
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000244TEST_F(MidiManagerTest, CreateMidiManager) {
245 scoped_ptr<FakeMidiManagerClient> client;
246 client.reset(new FakeMidiManagerClient(0));
247
248 scoped_ptr<MidiManager> manager(MidiManager::Create());
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +0000249 manager->StartSession(client.get(), client->client_id());
250
agoode@chromium.org25227512014-06-08 05:12:05 +0000251 MidiResult result = client->WaitForResult();
toyoshim@chromium.orga25e6832014-05-07 18:06:25 +0000252 // This #ifdef needs to be identical to the one in media/midi/midi_manager.cc.
253 // Do not change the condition for disabling this test.
dnicoara@chromium.orgc404df62014-05-06 22:56:00 +0000254#if !defined(OS_MACOSX) && !defined(OS_WIN) && !defined(USE_ALSA) && \
255 !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
agoode@chromium.org25227512014-06-08 05:12:05 +0000256 EXPECT_EQ(MIDI_NOT_SUPPORTED, result);
257#elif defined(USE_ALSA)
258 // Temporary until http://crbug.com/371230 is resolved.
259 EXPECT_TRUE((result == MIDI_OK) || (result == MIDI_INITIALIZATION_ERROR));
dnicoara@chromium.orgc404df62014-05-06 22:56:00 +0000260#else
agoode@chromium.org25227512014-06-08 05:12:05 +0000261 EXPECT_EQ(MIDI_OK, result);
dnicoara@chromium.orgc404df62014-05-06 22:56:00 +0000262#endif
toyoshim@chromium.orgc1e05fb2014-05-06 16:39:20 +0000263}
264
toyoshim@chromium.org51c7f532014-05-01 17:17:32 +0000265} // namespace
266
267} // namespace media