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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

1 schoenebeck 211 #include "LSCPTest.h"
2    
3 schoenebeck 217 #include "../common/global.h"
4     #include "../common/optional.h"
5    
6 schoenebeck 211 #include <iostream>
7     #include <stdio.h>
8     #include <stdlib.h>
9 schoenebeck 217 #include <unistd.h>
10 schoenebeck 211
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 schoenebeck 217 /// 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 schoenebeck 211 // 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 schoenebeck 217 /// 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 schoenebeck 211 return __ConvertMultiLineMessage(msg);
171     }
172    
173 schoenebeck 217 /// 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 schoenebeck 211 if (!hServerIn) {
176     cout << "receiveAnswerFromLSCPServer() error: client socket not ready\n" << flush;
177     return "";
178     }
179     string message;
180     char c;
181 schoenebeck 217 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 schoenebeck 211 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 schoenebeck 217 // 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 schoenebeck 211 // 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