/[svn]/linuxsampler/trunk/src/testcases/LSCPTest.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/testcases/LSCPTest.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 217 - (show annotations) (download)
Sun Aug 15 18:52:23 2004 UTC (19 years, 7 months ago) by schoenebeck
File size: 12507 byte(s)
added test for "GET AUDIO_OUTPUT_CHANNEL_PARAMETER INFO" LSCP command

1 #include "LSCPTest.h"
2
3 #include "../common/global.h"
4 #include "../common/optional.h"
5
6 #include <iostream>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10
11 CPPUNIT_TEST_SUITE_REGISTRATION(LSCPTest);
12
13 // Note:
14 // we have to declare all those variables which we want to use for all
15 // tests within this test suite static because there are side effects which
16 // occur on transition to the next test which would change the values of our
17 // variables
18 static Sampler* pSampler = NULL;
19 static LSCPServer* pLSCPServer = NULL;
20 static int hSocket = -1;
21 static FILE* hServerIn = NULL;
22
23 /// Returns first token from \a sentence and removes that token (and evtl. delimiter) from \a sentence.
24 static optional<string> __ExtractFirstToken(string* pSentence, const string Delimiter) {
25 if (*pSentence == "") return optional<string>::nothing;
26
27 string::size_type pos = pSentence->find(Delimiter);
28
29 // if sentence has only one token
30 if (pos == string::npos) {
31 string token = *pSentence;
32 *pSentence = "";
33 return token;
34 }
35
36 // sentence has more than one token, so extract the first token
37 string token = pSentence->substr(0, pos);
38 *pSentence = pSentence->replace(0, pos + 1, "");
39 return token;
40 }
41
42 // split the multi line response string into the individual lines and remove the last (delimiter) line and the line feed characters in all lines
43 static vector<string> __ConvertMultiLineMessage(string msg) {
44 vector<string> res;
45
46 // erase the (dot) delimiter line
47 static const string dotlinedelimiter = ".\r\n";
48 string::size_type pos = msg.rfind(dotlinedelimiter);
49 msg = msg.replace(pos, dotlinedelimiter.length(), "");
50
51 // now split the lines
52 static const string linedelimiter = "\r\n";
53 while (true) {
54 pos = msg.find(linedelimiter, 0);
55
56 if (pos == string::npos) break; // if we're done
57
58 // get the line without the line feed and put it at the end of the vector
59 string line = msg.substr(0, pos);
60 res.push_back(line);
61
62 // remove the line from the input string
63 pos += linedelimiter.length();
64 msg = msg.substr(pos, msg.length() - pos);
65 }
66
67 return res;
68 }
69
70
71 // LSCPTest
72
73 // returns false if the server could not be launched
74 bool LSCPTest::launchLSCPServer() {
75 const long timeout_seconds = 10; // we give the server max. 10 seconds to startup, otherwise we declare the startup as failed
76 try {
77 pSampler = new Sampler;
78 pLSCPServer = new LSCPServer(pSampler);
79 pLSCPServer->StartThread();
80 int res = pLSCPServer->WaitUntilInitialized(timeout_seconds);
81 if (res < 0) throw;
82
83 return true; // success
84 }
85 catch (...) {
86 pSampler = NULL;
87 pLSCPServer = NULL;
88 return false; // failure
89 }
90 }
91
92 // returns false if the server could not be destroyed without problems
93 bool LSCPTest::shutdownLSCPServer() {
94 try {
95 pLSCPServer->StopThread();
96 if (pLSCPServer) {
97 delete pLSCPServer;
98 pLSCPServer = NULL;
99 }
100 if (pSampler) {
101 delete pSampler;
102 pSampler = NULL;
103 }
104 return true; // success
105 }
106 catch (...) {
107 return false; // failure
108 }
109 }
110
111 // returns false if client connection to the LSCP server could not be established
112 bool LSCPTest::connectToLSCPServer() {
113 const int iPort = LSCP_PORT; // LSCP server listening port (from lscpserver.h)
114 hSocket = -1;
115
116 hostent* pHost = gethostbyname("localhost");
117 if (pHost == NULL) return false;
118
119 hSocket = socket(AF_INET, SOCK_STREAM, 0);
120 if (hSocket < 0) return false;
121
122 sockaddr_in addr;
123 memset((char*) &addr, 0, sizeof(sockaddr_in));
124 addr.sin_family = pHost->h_addrtype;
125 memmove((char*) &(addr.sin_addr), pHost->h_addr, pHost->h_length);
126 addr.sin_port = htons((short) iPort);
127
128 if (connect(hSocket, (sockaddr*) &addr, sizeof(sockaddr_in)) < 0) {
129 close(hSocket);
130 return false;
131 }
132
133 hServerIn = fdopen(hSocket, "r");
134
135 return true;
136 }
137
138 bool LSCPTest::closeConnectionToLSCPServer() {
139 //cout << "closeConnectionToLSCPServer()\n" << flush;
140 hServerIn = NULL;
141 if (hSocket >= 0) {
142 close(hSocket);
143 hSocket = -1;
144 }
145 return true;
146 }
147
148 // send a command to the LSCP server
149 void LSCPTest::sendCommandToLSCPServer(string cmd) {
150 if (hSocket < 0) {
151 cout << "sendCommandToLSCPServer() error: client socket not ready\n" << flush;
152 return;
153 }
154 cmd += "\r\n";
155 send(hSocket, cmd.c_str(), cmd.length(), 0);
156 }
157
158 // wait until LSCP server answers with a single line answer
159 string LSCPTest::receiveSingleLineAnswerFromLSCPServer() {
160 string msg = receiveAnswerFromLSCPServer("\n");
161 // remove the line feed at the end
162 static const string linedelimiter = "\r\n";
163 string::size_type pos = msg.rfind(linedelimiter);
164 return msg.substr(0, pos);
165 }
166
167 /// wait until LSCP server answers with a multi line answer (throws LinuxSamplerException if optional timeout exceeded)
168 vector<string> LSCPTest::receiveMultiLineAnswerFromLSCPServer(uint timeout_seconds) throw (LinuxSamplerException) {
169 string msg = receiveAnswerFromLSCPServer("\n.\r\n", timeout_seconds);
170 return __ConvertMultiLineMessage(msg);
171 }
172
173 /// wait until LSCP server answers with the given \a delimiter token at the end (throws LinuxSamplerException if optional timeout exceeded or socket error occured)
174 string LSCPTest::receiveAnswerFromLSCPServer(string delimiter, uint timeout_seconds) throw (LinuxSamplerException) {
175 if (!hServerIn) {
176 cout << "receiveAnswerFromLSCPServer() error: client socket not ready\n" << flush;
177 return "";
178 }
179 string message;
180 char c;
181 fd_set sockSet;
182 timeval timeout;
183
184 while (true) {
185 if (timeout_seconds) {
186 FD_ZERO(&sockSet);
187 FD_SET(hSocket, &sockSet);
188 timeout.tv_sec = timeout_seconds;
189 timeout.tv_usec = 0;
190 int res = select(hSocket + 1, &sockSet, NULL, NULL, &timeout);
191 if (!res) throw LinuxSamplerException("LSCPTest::receiveAnswerFromLSCPServer(): timeout (" + ToString(timeout_seconds) + "s) exceeded waiting for expected answer (end)");
192 else if (res < 0) throw LinuxSamplerException("LSCPTest::receiveAnswerFromLSCPServer(): select error");
193 }
194
195 // there's something to read, so read one character
196 c = fgetc(hServerIn);
197 if (c == EOF) {
198 cout << "receiveAnswerFromLSCPServer() error: EOF reached\n" << flush;
199 return "";
200 }
201 message += c;
202 string::size_type pos = message.rfind(delimiter); // ouch, but this is only a test case, right? ;)
203 if (pos != string::npos) return message;
204 }
205 }
206
207
208
209 void LSCPTest::printTestSuiteName() {
210 cout << "\b \nRunning LSCP Tests: " << flush;
211 }
212
213 void LSCPTest::setUp() {
214 }
215
216 void LSCPTest::tearDown() {
217 }
218
219
220
221 // Check if we can launch the LSCP Server (implies that there's no other instance running at the moment).
222 void LSCPTest::testLaunchLSCPServer() {
223 //cout << "testLaunchLSCPServer()\n" << flush;
224 CPPUNIT_ASSERT(launchLSCPServer());
225 }
226
227 // Check if we can connect a client connection to the LSCP server and close that connection without problems.
228 void LSCPTest::testConnectToLSCPServer() {
229 //cout << "testConnectToLSCPServer()\n" << flush;
230 sleep(1); // wait 1s
231 CPPUNIT_ASSERT(connectToLSCPServer());
232 sleep(2); // wait 2s
233 CPPUNIT_ASSERT(closeConnectionToLSCPServer());
234 }
235
236 // Check "ADD CHANNEL" LSCP command.
237 void LSCPTest::test_ADD_CHANNEL() {
238 sleep(1); // wait 1s
239 CPPUNIT_ASSERT(connectToLSCPServer());
240
241 sendCommandToLSCPServer("ADD CHANNEL");
242 CPPUNIT_ASSERT(receiveSingleLineAnswerFromLSCPServer() == "OK[0]");
243
244 sendCommandToLSCPServer("ADD CHANNEL");
245 CPPUNIT_ASSERT(receiveSingleLineAnswerFromLSCPServer() == "OK[1]");
246
247 sendCommandToLSCPServer("ADD CHANNEL");
248 CPPUNIT_ASSERT(receiveSingleLineAnswerFromLSCPServer() == "OK[2]");
249 }
250
251 // Check "GET CHANNELS" LSCP command.
252 void LSCPTest::test_GET_CHANNELS() {
253 sendCommandToLSCPServer("GET CHANNELS");
254 string answer = receiveSingleLineAnswerFromLSCPServer();
255 int initial_channels = atoi(answer.c_str());
256
257 // add sampler channels and check if the count increases
258 for (uint trial = 1; trial <= 3; trial++) {
259 sendCommandToLSCPServer("ADD CHANNEL");
260 answer = receiveSingleLineAnswerFromLSCPServer();
261 sendCommandToLSCPServer("GET CHANNELS");
262 answer = receiveSingleLineAnswerFromLSCPServer();
263 int channels = atoi(answer.c_str());
264 CPPUNIT_ASSERT(channels == initial_channels + trial);
265 }
266 }
267
268 // Check "REMOVE CHANNEL" LSCP command.
269 void LSCPTest::test_REMOVE_CHANNEL() {
270 // how many channels do we have at the moment?
271 sendCommandToLSCPServer("GET CHANNELS");
272 string answer = receiveSingleLineAnswerFromLSCPServer();
273 int initial_channels = atoi(answer.c_str());
274
275 // if there are no sampler channels yet, create some
276 if (!initial_channels) {
277 const uint create_channels = 4;
278 for (uint i = 0; i < create_channels; i++) {
279 sendCommandToLSCPServer("ADD CHANNEL");
280 answer = receiveSingleLineAnswerFromLSCPServer();
281 }
282 initial_channels = create_channels;
283 }
284
285 // now remove the channels until there is no one left and check if we really need 'initial_channels' times to achieve that
286 for (uint channels = initial_channels; channels; channels--) {
287 sendCommandToLSCPServer("LIST CHANNELS");
288 answer = receiveSingleLineAnswerFromLSCPServer();
289 if (answer == "") CPPUNIT_ASSERT(false); // no sampler channel left already? -> failure
290
291 // take the last channel number in the list which we will take to remove that sampler channel
292 string::size_type pos = answer.rfind(",");
293 string channel_to_remove = (pos != string::npos) ? answer.substr(pos + 1, answer.length() - (pos + 1)) /* "m,n,...,t */
294 : answer; /* "k" */
295
296 //cout << " channel_to_remove: \"" << channel_to_remove << "\"\n" << flush;
297
298 // remove that channel
299 sendCommandToLSCPServer("REMOVE CHANNEL " + channel_to_remove);
300 answer = receiveSingleLineAnswerFromLSCPServer();
301 CPPUNIT_ASSERT(answer == "OK");
302 }
303 CPPUNIT_ASSERT(true); // success
304 }
305
306 // Check "GET AUDIO_OUTPUT_CHANNEL_PARAMETER INFO" LSCP command.
307 void LSCPTest::test_GET_AUDIO_OUTPUT_CHANNEL_PARAMETER_INFO() {
308 // first check if there's already an audio output device created
309 sendCommandToLSCPServer("GET AUDIO_OUTPUT_DEVICES");
310 string answer = receiveSingleLineAnswerFromLSCPServer();
311 int devices = atoi(answer.c_str());
312 CPPUNIT_ASSERT(devices >= 0);
313 if (!devices) { // if there's no audio output device yet, try to create one
314 sendCommandToLSCPServer("GET AVAILABLE_AUDIO_OUTPUT_DRIVERS");
315 string drivers = receiveSingleLineAnswerFromLSCPServer();
316 CPPUNIT_ASSERT(drivers.size());
317
318 // iterate through all available drivers until device creation was successful
319 do {
320 optional<string> driver = __ExtractFirstToken(&drivers, ",");
321 CPPUNIT_ASSERT(driver);
322
323 sendCommandToLSCPServer("CREATE AUDIO_OUTPUT_DEVICE " + *driver);
324 answer = receiveSingleLineAnswerFromLSCPServer();
325 } while (answer != "OK[0]");
326 }
327
328 // now we can check the "GET AUDIO_OUTPUT_CHANNEL_PARAMETER INFO" command
329 const uint timeout_seconds = 2;
330 sendCommandToLSCPServer("GET AUDIO_OUTPUT_CHANNEL_PARAMETER INFO 0 0 NAME");
331 vector<string> vAnswer = receiveMultiLineAnswerFromLSCPServer(timeout_seconds);
332 CPPUNIT_ASSERT(vAnswer.size() >= 4); // should at least contain tags TYPE, DESCRIPTION, FIX and MULTIPLICITY
333
334 sendCommandToLSCPServer("GET AUDIO_OUTPUT_CHANNEL_PARAMETER INFO 0 0 IS_MIX_CHANNEL");
335 vAnswer = receiveMultiLineAnswerFromLSCPServer(timeout_seconds);
336 CPPUNIT_ASSERT(vAnswer.size() >= 4); // should at least contain tags TYPE, DESCRIPTION, FIX and MULTIPLICITY
337 }
338
339 // Check if we can shutdown the LSCP Server without problems.
340 void LSCPTest::testShutdownLSCPServer() {
341 //cout << "testShutdownLSCPServer()\n" << flush;
342 sleep(2); // wait 2s
343 CPPUNIT_ASSERT(closeConnectionToLSCPServer());
344 sleep(3); // wait 3s
345 CPPUNIT_ASSERT(shutdownLSCPServer());
346 }

  ViewVC Help
Powered by ViewVC