1 |
#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 |
} |