Skip to content

Commit 52da280

Browse files
dsavenkoDVEfremov
authored andcommitted
Run tests on CI + some improvements (#8)
* Run tests on Travis build * Clone the latest CK for tests * Some tests refactoring * Migrate tests to python * Minor * Minor * Minor * Minor * Minor * Minor * Minor * No default secret key * Add secret key to the tests * Specify correct env vars for ck-crowdnode from tests * Fix dealing with configs * Detect the length of incoming request * Minor * Migrate the shell test to the new runner
1 parent 80b26e5 commit 52da280

14 files changed

+219
-43
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"port":3334,
2+
"port":3333,
33
"path_to_files":"$HOME/ck-crowdnode-files",
44
"secret_key":"c4e239b4-8471-11e6-b24d-cbfef11692ca"
55
}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
build
2+
*.pyc

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
language: c
2-
script: ./_compile.sh
2+
script: "./_compile.sh && python -m run_tests.py"
33
compiler:
44
- clang
55
- gcc

appveyor.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1+
environment:
2+
matrix:
3+
- PYTHON: "C:\\Python27"
14

25
build:
36

47
build_script:
58
- mkdir build
69
- cd build
710
- cmake ..
8-
- ls C:/projects/ck-crowdnode/build
911
- msbuild /p:Configuration=Release /p:Platform=Win32 C:/projects/ck-crowdnode/build/Project.sln
12+
- ls C:/projects/ck-crowdnode/build
13+
- ls Release
14+
- cp Release/ck-crowdnode-server.exe .
15+
- cd ..
16+
- "%PYTHON%/python.exe -m run_tests.py"

run_tests.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#!/usr/bin/python
2+
3+
from __future__ import print_function
4+
import subprocess
5+
import shutil
6+
import os
7+
import sys
8+
import unittest
9+
import time
10+
import platform
11+
12+
def safe_remove(fname):
13+
try:
14+
os.remove(fname)
15+
except Exception:
16+
pass
17+
18+
script_dir = os.path.dirname(os.path.realpath(__file__))
19+
os.chdir(script_dir)
20+
21+
config_dir = os.path.join(script_dir, '.ck-crowdnode')
22+
config_file = os.path.join(config_dir, 'ck-crowdnode-config.json')
23+
config_file_sample_windows = os.path.join(config_dir, 'ck-crowdnode-config.json.windows.sample')
24+
config_file_sample_linux = os.path.join(config_dir, 'ck-crowdnode-config.json.linux.sample')
25+
26+
files_dir = os.path.join(script_dir, 'ck-crowdnode-files')
27+
if not os.path.exists(files_dir):
28+
os.makedirs(files_dir)
29+
30+
node_process=None
31+
ck_dir='tests-ck-master'
32+
33+
def die(retcode):
34+
os.chdir(script_dir)
35+
shutil.rmtree(ck_dir, ignore_errors=True)
36+
shutil.rmtree(files_dir, ignore_errors=True)
37+
safe_remove(config_file)
38+
if node_process is not None:
39+
node_process.kill()
40+
exit(retcode)
41+
42+
safe_remove(config_file)
43+
node_env = os.environ.copy()
44+
if 'Windows' == platform.system():
45+
node_env['LOCALAPPDATA'] = script_dir
46+
shutil.copyfile(config_file_sample_windows, config_file)
47+
else:
48+
node_env['HOME'] = script_dir
49+
shutil.copyfile(config_file_sample_linux, config_file)
50+
51+
node_process = subprocess.Popen(['build/ck-crowdnode-server'], env=node_env)
52+
53+
shutil.rmtree(ck_dir, ignore_errors=True)
54+
r = subprocess.call('git clone https://github.com/ctuning/ck.git ' + ck_dir, shell=True)
55+
if 0 < r:
56+
print('Error: failed to clone CK!')
57+
die(1)
58+
59+
sys.path.append(ck_dir)
60+
61+
import ck.kernel as ck
62+
63+
r = ck.access({'remote': 'yes', 'module_uoa': 'repo', 'url': 'http://localhost:3333', 'quiet': 'yes', 'data_uoa': 'remote-ck-node', 'action': 'add'})
64+
65+
tests_dir = os.path.join(script_dir, 'tests')
66+
67+
class CkTestLoader(unittest.TestLoader):
68+
def loadTestsFromModule(self, module, pattern=None):
69+
module.ck = ck
70+
module.secret_key = 'c4e239b4-8471-11e6-b24d-cbfef11692ca'
71+
module.platform = platform.system()
72+
return unittest.TestLoader.loadTestsFromModule(self, module, pattern)
73+
74+
suite = CkTestLoader().discover(tests_dir, pattern='test_*.py')
75+
76+
os.chdir(tests_dir)
77+
test_result = unittest.TextTestRunner().run(suite)
78+
79+
die(0 if test_result.wasSuccessful() else 1)

src/ck-crowdnode-server.c

Lines changed: 83 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,47 @@ int WSAGetLastError() {
125125

126126
void doProcessing(int sock, char *baseDir);
127127

128+
int sockSend(int sock, const void* buf, size_t len) {
129+
#ifdef _WIN32
130+
return send(sock, buf, len, 0);
131+
#else
132+
return write(sock, buf, len);
133+
#endif
134+
}
135+
136+
int sockSendAll(int sock, const void* buf, size_t len) {
137+
const char* p = buf;
138+
while (0 < len) {
139+
int n = sockSend(sock, p, len);
140+
if (0 >= n) {
141+
return -1;
142+
}
143+
p += n;
144+
len -= n;
145+
}
146+
return 0;
147+
}
148+
149+
int sendHttpResponse(int sock, int httpStatus, char* payload, int size) {
150+
// send HTTP headers
151+
char buf[200];
152+
int n = sprintf(buf, "HTTP/1.1 %d OK\r\nContent-Length: %d\r\n\r\n", httpStatus, size);
153+
if (0 >= n) {
154+
perror("sprintf failed");
155+
return -1;
156+
}
157+
if (0 > sockSendAll(sock, buf, n)) {
158+
perror("Failed to send HTTP response headers");
159+
return -1;
160+
}
161+
162+
// send payload
163+
if (0 > sockSendAll(sock, payload, size)) {
164+
perror("Failed to send HTTP response body");
165+
return -1;
166+
}
167+
}
168+
128169
void sendErrorMessage(int sock, char * errorMessage, const char *errorCode) {
129170
perror(errorMessage);
130171

@@ -141,12 +182,7 @@ void sendErrorMessage(int sock, char * errorMessage, const char *errorCode) {
141182
perror("[ERROR]: resultJSONtext cannot be created");
142183
return;
143184
}
144-
#ifdef _WIN32
145-
int n =send( sock, resultJSONtext, strlen(resultJSONtext), 0 );
146-
#else
147-
int n = write(sock, resultJSONtext, strlen(resultJSONtext));
148-
#endif
149-
185+
int n = sendHttpResponse(sock, 500, resultJSONtext, strlen(resultJSONtext));
150186
if (n < 0) {
151187
perror("ERROR writing to socket");
152188
return ;
@@ -530,7 +566,41 @@ void doProcessingWin (struct thread_win_params* ptwp)
530566
}
531567
#endif
532568

569+
/**
570+
* Tries to detect message length by the given buffer, which contains the beginning of the message.
571+
* The buffer passed must be of at least (size+1) length.
572+
*
573+
* Returns -1, if the length is still unknown (in this case the caller must provide a bigger part of the message).
574+
*
575+
* Returns -2, if the length can never be determined, i.e. HTTP headers don't contain 'Content-Length'.
576+
*
577+
* If 0 or more is returned, it is the total size of the message (size of the headers + size of the body).
578+
*/
579+
int detectMessageLength(char* buf, int size) {
580+
buf[size] = 0;
581+
582+
// trying to find where headers end
583+
char* s = strstr(buf, "\r\n\r\n");
584+
int header_stop_len = 4;
585+
if (NULL == s) {
586+
s = strstr(buf, "\n\n");
587+
header_stop_len = 2;
588+
}
589+
if (NULL == s) {
590+
return -1;
591+
}
592+
const long header_len = (s - buf) + header_stop_len;
593+
594+
const char* content_len_key = "Content-Length:";
595+
// trying to find Content-Length
596+
char* content_len_header = strstr(buf, content_len_key);
597+
if (NULL == content_len_header || (content_len_header - buf) >= header_len) {
598+
return -2;
599+
}
533600

601+
long l = strtol(content_len_header + strlen(content_len_key), NULL, 10);
602+
return header_len + l;
603+
}
534604

535605
void doProcessing(int sock, char *baseDir) {
536606
char *client_message = malloc(MAX_BUFFER_SIZE + 1);
@@ -548,6 +618,7 @@ void doProcessing(int sock, char *baseDir) {
548618
memset(buffer, 0, MAX_BUFFER_SIZE);
549619
int buffer_read = 0;
550620
int total_read = 0;
621+
int message_len = -1;
551622

552623
//buffered read from socket
553624
int i = 0;
@@ -564,12 +635,15 @@ void doProcessing(int sock, char *baseDir) {
564635
total_read = total_read + buffer_read;
565636
printf("Next %i part of buffer\n", i);
566637
i++;
638+
if (-1 == message_len) {
639+
message_len = detectMessageLength(buffer, total_read);
640+
}
567641
} else if (buffer_read < 0) {
568642
perror("[ERROR]: reading from socket");
569643
printf("WSAGetLastError() %i\n", WSAGetLastError()); //win
570644
exit(1);
571645
}
572-
if (buffer_read == 0 || buffer_read < MAX_BUFFER_SIZE) {
646+
if (buffer_read == 0 || total_read >= message_len || -2 == message_len) {
573647
/* message received successfully */
574648
break;
575649
}
@@ -607,10 +681,8 @@ void doProcessing(int sock, char *baseDir) {
607681
return;
608682
}
609683
char *clientSecretKey = secretkeyJSON->valuestring;
610-
printf("[ERROR]: Get secretkey: %s from client\n", clientSecretKey);
684+
printf("[DEBUG]: Got secretkey: %s from client\n", clientSecretKey);
611685
if (!serverSecretKey || strncmp(clientSecretKey, serverSecretKey, strlen(serverSecretKey)) == 0 ) {
612-
613-
614686
cJSON *actionJSON = cJSON_GetObjectItem(commandJSON, JSON_PARAM_NAME_COMMAND);
615687
if (!actionJSON) {
616688
printf("[ERROR]: Invalid action JSON format for message: \n");
@@ -879,11 +951,7 @@ void doProcessing(int sock, char *baseDir) {
879951
sendErrorMessage(sock, "unknown action", ERROR_CODE);
880952
}
881953

882-
#ifdef _WIN32
883-
int n1 =send( sock, resultJSONtext, strlen(resultJSONtext), 0 );
884-
#else
885-
int n1 = write(sock, resultJSONtext, strlen(resultJSONtext));
886-
#endif
954+
int n1 = sendHttpResponse(sock, 200, resultJSONtext, strlen(resultJSONtext));
887955

888956
free(resultJSONtext);
889957

tests/_pull.bat

Lines changed: 0 additions & 4 deletions
This file was deleted.

tests/_pull.sh

Lines changed: 0 additions & 5 deletions
This file was deleted.

tests/_push.bat

Lines changed: 0 additions & 3 deletions
This file was deleted.

tests/_push.sh

Lines changed: 0 additions & 4 deletions
This file was deleted.

0 commit comments

Comments
 (0)