1 |
schoenebeck |
211 |
#include "LSCPTest.h" |
2 |
|
|
|
3 |
|
|
#include <iostream> |
4 |
|
|
#include <stdio.h> |
5 |
|
|
#include <stdlib.h> |
6 |
|
|
|
7 |
|
|
CPPUNIT_TEST_SUITE_REGISTRATION(LSCPTest); |
8 |
|
|
|
9 |
|
|
// Note: |
10 |
|
|
// we have to declare all those variables which we want to use for all |
11 |
|
|
// tests within this test suite static because there are side effects which |
12 |
|
|
// occur on transition to the next test which would change the values of our |
13 |
|
|
// variables |
14 |
|
|
static Sampler* pSampler = NULL; |
15 |
|
|
static LSCPServer* pLSCPServer = NULL; |
16 |
|
|
static int hSocket = -1; |
17 |
|
|
static FILE* hServerIn = NULL; |
18 |
|
|
|
19 |
|
|
// split the multi line response string into the individual lines and remove the last (delimiter) line and the line feed characters in all lines |
20 |
|
|
static vector<string> __ConvertMultiLineMessage(string msg) { |
21 |
|
|
vector<string> res; |
22 |
|
|
|
23 |
|
|
// erase the (dot) delimiter line |
24 |
|
|
static const string dotlinedelimiter = ".\r\n"; |
25 |
|
|
string::size_type pos = msg.rfind(dotlinedelimiter); |
26 |
|
|
msg = msg.replace(pos, dotlinedelimiter.length(), ""); |
27 |
|
|
|
28 |
|
|
// now split the lines |
29 |
|
|
static const string linedelimiter = "\r\n"; |
30 |
|
|
while (true) { |
31 |
|
|
pos = msg.find(linedelimiter, 0); |
32 |
|
|
|
33 |
|
|
if (pos == string::npos) break; // if we're done |
34 |
|
|
|
35 |
|
|
// get the line without the line feed and put it at the end of the vector |
36 |
|
|
string line = msg.substr(0, pos); |
37 |
|
|
res.push_back(line); |
38 |
|
|
|
39 |
|
|
// remove the line from the input string |
40 |
|
|
pos += linedelimiter.length(); |
41 |
|
|
msg = msg.substr(pos, msg.length() - pos); |
42 |
|
|
} |
43 |
|
|
|
44 |
|
|
return res; |
45 |
|
|
} |
46 |
|
|
|
47 |
|
|
|
48 |
|
|
// LSCPTest |
49 |
|
|
|
50 |
|
|
// returns false if the server could not be launched |
51 |
|
|
bool LSCPTest::launchLSCPServer() { |
52 |
|
|
const long timeout_seconds = 10; // we give the server max. 10 seconds to startup, otherwise we declare the startup as failed |
53 |
|
|
try { |
54 |
|
|
pSampler = new Sampler; |
55 |
|
|
pLSCPServer = new LSCPServer(pSampler); |
56 |
|
|
pLSCPServer->StartThread(); |
57 |
|
|
int res = pLSCPServer->WaitUntilInitialized(timeout_seconds); |
58 |
|
|
if (res < 0) throw; |
59 |
|
|
|
60 |
|
|
return true; // success |
61 |
|
|
} |
62 |
|
|
catch (...) { |
63 |
|
|
pSampler = NULL; |
64 |
|
|
pLSCPServer = NULL; |
65 |
|
|
return false; // failure |
66 |
|
|
} |
67 |
|
|
} |
68 |
|
|
|
69 |
|
|
// returns false if the server could not be destroyed without problems |
70 |
|
|
bool LSCPTest::shutdownLSCPServer() { |
71 |
|
|
try { |
72 |
|
|
pLSCPServer->StopThread(); |
73 |
|
|
if (pLSCPServer) { |
74 |
|
|
delete pLSCPServer; |
75 |
|
|
pLSCPServer = NULL; |
76 |
|
|
} |
77 |
|
|
if (pSampler) { |
78 |
|
|
delete pSampler; |
79 |
|
|
pSampler = NULL; |
80 |
|
|
} |
81 |
|
|
return true; // success |
82 |
|
|
} |
83 |
|
|
catch (...) { |
84 |
|
|
return false; // failure |
85 |
|
|
} |
86 |
|
|
} |
87 |
|
|
|
88 |
|
|
// returns false if client connection to the LSCP server could not be established |
89 |
|
|
bool LSCPTest::connectToLSCPServer() { |
90 |
|
|
const int iPort = LSCP_PORT; // LSCP server listening port (from lscpserver.h) |
91 |
|
|
hSocket = -1; |
92 |
|
|
|
93 |
|
|
hostent* pHost = gethostbyname("localhost"); |
94 |
|
|
if (pHost == NULL) return false; |
95 |
|
|
|
96 |
|
|
hSocket = socket(AF_INET, SOCK_STREAM, 0); |
97 |
|
|
if (hSocket < 0) return false; |
98 |
|
|
|
99 |
|
|
sockaddr_in addr; |
100 |
|
|
memset((char*) &addr, 0, sizeof(sockaddr_in)); |
101 |
|
|
addr.sin_family = pHost->h_addrtype; |
102 |
|
|
memmove((char*) &(addr.sin_addr), pHost->h_addr, pHost->h_length); |
103 |
|
|
addr.sin_port = htons((short) iPort); |
104 |
|
|
|
105 |
|
|
if (connect(hSocket, (sockaddr*) &addr, sizeof(sockaddr_in)) < 0) { |
106 |
|
|
close(hSocket); |
107 |
|
|
return false; |
108 |
|
|
} |
109 |
|
|
|
110 |
|
|
hServerIn = fdopen(hSocket, "r"); |
111 |
|
|
|
112 |
|
|
return true; |
113 |
|
|
} |
114 |
|
|
|
115 |
|
|
bool LSCPTest::closeConnectionToLSCPServer() { |
116 |
|
|
//cout << "closeConnectionToLSCPServer()\n" << flush; |
117 |
|
|
hServerIn = NULL; |
118 |
|
|
if (hSocket >= 0) { |
119 |
|
|
close(hSocket); |
120 |
|
|
hSocket = -1; |
121 |
|
|
} |
122 |
|
|
return true; |
123 |
|
|
} |
124 |
|
|
|
125 |
|
|
// send a command to the LSCP server |
126 |
|
|
void LSCPTest::sendCommandToLSCPServer(string cmd) { |
127 |
|
|
if (hSocket < 0) { |
128 |
|
|
cout << "sendCommandToLSCPServer() error: client socket not ready\n" << flush; |
129 |
|
|
return; |
130 |
|
|
} |
131 |
|
|
cmd += "\r\n"; |
132 |
|
|
send(hSocket, cmd.c_str(), cmd.length(), 0); |
133 |
|
|
} |
134 |
|
|
|
135 |
|
|
// wait until LSCP server answers with a single line answer |
136 |
|
|
string LSCPTest::receiveSingleLineAnswerFromLSCPServer() { |
137 |
|
|
string msg = receiveAnswerFromLSCPServer("\n"); |
138 |
|
|
// remove the line feed at the end |
139 |
|
|
static const string linedelimiter = "\r\n"; |
140 |
|
|
string::size_type pos = msg.rfind(linedelimiter); |
141 |
|
|
return msg.substr(0, pos); |
142 |
|
|
} |
143 |
|
|
|
144 |
|
|
// wait until LSCP server answers with a multi line answer |
145 |
|
|
vector<string> LSCPTest::receiveMultiLineAnswerFromLSCPServer() { |
146 |
|
|
string msg = receiveAnswerFromLSCPServer("\n.\r\n"); |
147 |
|
|
return __ConvertMultiLineMessage(msg); |
148 |
|
|
} |
149 |
|
|
|
150 |
|
|
// wait until LSCP server answers with the given \a delimiter token at the end |
151 |
|
|
string LSCPTest::receiveAnswerFromLSCPServer(string delimiter) { |
152 |
|
|
if (!hServerIn) { |
153 |
|
|
cout << "receiveAnswerFromLSCPServer() error: client socket not ready\n" << flush; |
154 |
|
|
return ""; |
155 |
|
|
} |
156 |
|
|
string message; |
157 |
|
|
char c; |
158 |
|
|
while ((c = fgetc(hServerIn)) != EOF) { |
159 |
|
|
message += c; |
160 |
|
|
string::size_type pos = message.rfind(delimiter); // ouch, but this is only a test case, right? ;) |
161 |
|
|
if (pos != string::npos) return message; |
162 |
|
|
} |
163 |
|
|
cout << "receiveAnswerFromLSCPServer() error: EOF reached\n" << flush; |
164 |
|
|
return ""; |
165 |
|
|
} |
166 |
|
|
|
167 |
|
|
|
168 |
|
|
|
169 |
|
|
void LSCPTest::printTestSuiteName() { |
170 |
|
|
cout << "\b \nRunning LSCP Tests: " << flush; |
171 |
|
|
} |
172 |
|
|
|
173 |
|
|
void LSCPTest::setUp() { |
174 |
|
|
} |
175 |
|
|
|
176 |
|
|
void LSCPTest::tearDown() { |
177 |
|
|
} |
178 |
|
|
|
179 |
|
|
|
180 |
|
|
|
181 |
|
|
// Check if we can launch the LSCP Server (implies that there's no other instance running at the moment). |
182 |
|
|
void LSCPTest::testLaunchLSCPServer() { |
183 |
|
|
//cout << "testLaunchLSCPServer()\n" << flush; |
184 |
|
|
CPPUNIT_ASSERT(launchLSCPServer()); |
185 |
|
|
} |
186 |
|
|
|
187 |
|
|
// Check if we can connect a client connection to the LSCP server and close that connection without problems. |
188 |
|
|
void LSCPTest::testConnectToLSCPServer() { |
189 |
|
|
//cout << "testConnectToLSCPServer()\n" << flush; |
190 |
|
|
sleep(1); // wait 1s |
191 |
|
|
CPPUNIT_ASSERT(connectToLSCPServer()); |
192 |
|
|
sleep(2); // wait 2s |
193 |
|
|
CPPUNIT_ASSERT(closeConnectionToLSCPServer()); |
194 |
|
|
} |
195 |
|
|
|
196 |
|
|
// Check "ADD CHANNEL" LSCP command. |
197 |
|
|
void LSCPTest::test_ADD_CHANNEL() { |
198 |
|
|
sleep(1); // wait 1s |
199 |
|
|
CPPUNIT_ASSERT(connectToLSCPServer()); |
200 |
|
|
|
201 |
|
|
sendCommandToLSCPServer("ADD CHANNEL"); |
202 |
|
|
CPPUNIT_ASSERT(receiveSingleLineAnswerFromLSCPServer() == "OK[0]"); |
203 |
|
|
|
204 |
|
|
sendCommandToLSCPServer("ADD CHANNEL"); |
205 |
|
|
CPPUNIT_ASSERT(receiveSingleLineAnswerFromLSCPServer() == "OK[1]"); |
206 |
|
|
|
207 |
|
|
sendCommandToLSCPServer("ADD CHANNEL"); |
208 |
|
|
CPPUNIT_ASSERT(receiveSingleLineAnswerFromLSCPServer() == "OK[2]"); |
209 |
|
|
} |
210 |
|
|
|
211 |
|
|
// Check "GET CHANNELS" LSCP command. |
212 |
|
|
void LSCPTest::test_GET_CHANNELS() { |
213 |
|
|
sendCommandToLSCPServer("GET CHANNELS"); |
214 |
|
|
string answer = receiveSingleLineAnswerFromLSCPServer(); |
215 |
|
|
int initial_channels = atoi(answer.c_str()); |
216 |
|
|
|
217 |
|
|
// add sampler channels and check if the count increases |
218 |
|
|
for (uint trial = 1; trial <= 3; trial++) { |
219 |
|
|
sendCommandToLSCPServer("ADD CHANNEL"); |
220 |
|
|
answer = receiveSingleLineAnswerFromLSCPServer(); |
221 |
|
|
sendCommandToLSCPServer("GET CHANNELS"); |
222 |
|
|
answer = receiveSingleLineAnswerFromLSCPServer(); |
223 |
|
|
int channels = atoi(answer.c_str()); |
224 |
|
|
CPPUNIT_ASSERT(channels == initial_channels + trial); |
225 |
|
|
} |
226 |
|
|
} |
227 |
|
|
|
228 |
|
|
// Check "REMOVE CHANNEL" LSCP command. |
229 |
|
|
void LSCPTest::test_REMOVE_CHANNEL() { |
230 |
|
|
// how many channels do we have at the moment? |
231 |
|
|
sendCommandToLSCPServer("GET CHANNELS"); |
232 |
|
|
string answer = receiveSingleLineAnswerFromLSCPServer(); |
233 |
|
|
int initial_channels = atoi(answer.c_str()); |
234 |
|
|
|
235 |
|
|
// if there are no sampler channels yet, create some |
236 |
|
|
if (!initial_channels) { |
237 |
|
|
const uint create_channels = 4; |
238 |
|
|
for (uint i = 0; i < create_channels; i++) { |
239 |
|
|
sendCommandToLSCPServer("ADD CHANNEL"); |
240 |
|
|
answer = receiveSingleLineAnswerFromLSCPServer(); |
241 |
|
|
} |
242 |
|
|
initial_channels = create_channels; |
243 |
|
|
} |
244 |
|
|
|
245 |
|
|
// now remove the channels until there is no one left and check if we really need 'initial_channels' times to achieve that |
246 |
|
|
for (uint channels = initial_channels; channels; channels--) { |
247 |
|
|
sendCommandToLSCPServer("LIST CHANNELS"); |
248 |
|
|
answer = receiveSingleLineAnswerFromLSCPServer(); |
249 |
|
|
if (answer == "") CPPUNIT_ASSERT(false); // no sampler channel left already? -> failure |
250 |
|
|
|
251 |
|
|
// take the last channel number in the list which we will take to remove that sampler channel |
252 |
|
|
string::size_type pos = answer.rfind(","); |
253 |
|
|
string channel_to_remove = (pos != string::npos) ? answer.substr(pos + 1, answer.length() - (pos + 1)) /* "m,n,...,t */ |
254 |
|
|
: answer; /* "k" */ |
255 |
|
|
|
256 |
|
|
//cout << " channel_to_remove: \"" << channel_to_remove << "\"\n" << flush; |
257 |
|
|
|
258 |
|
|
// remove that channel |
259 |
|
|
sendCommandToLSCPServer("REMOVE CHANNEL " + channel_to_remove); |
260 |
|
|
answer = receiveSingleLineAnswerFromLSCPServer(); |
261 |
|
|
CPPUNIT_ASSERT(answer == "OK"); |
262 |
|
|
} |
263 |
|
|
CPPUNIT_ASSERT(true); // success |
264 |
|
|
} |
265 |
|
|
|
266 |
|
|
// Check if we can shutdown the LSCP Server without problems. |
267 |
|
|
void LSCPTest::testShutdownLSCPServer() { |
268 |
|
|
//cout << "testShutdownLSCPServer()\n" << flush; |
269 |
|
|
sleep(2); // wait 2s |
270 |
|
|
CPPUNIT_ASSERT(closeConnectionToLSCPServer()); |
271 |
|
|
sleep(3); // wait 3s |
272 |
|
|
CPPUNIT_ASSERT(shutdownLSCPServer()); |
273 |
|
|
} |