log_collection_tester.c 9.51 KB
Newer Older
1
/*
2 3
	Linphone
	Copyright (C) 2014  Belledonne Communications SARL
4

5 6 7 8
	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 2 of the License, or
	(at your option) any later version.
9

10 11 12 13
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
14

15 16
	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 18
*/

Ghislain MARY's avatar
Ghislain MARY committed
19 20
#ifndef _XOPEN_SOURCE
	#define _XOPEN_SOURCE 700 // To have definition of strptime, snprintf and getline
21
#endif
22
#include <time.h>
23
#include "linphone/core.h"
24
#include "liblinphone_tester.h"
Benjamin REIS's avatar
Benjamin REIS committed
25
#include "tester_utils.h"
26

27 28 29 30
#ifdef HAVE_ZLIB
#include <zlib.h>
#endif

31

32
/*getline is POSIX 2008, not available on many systems.*/
33
#if (defined(__ANDROID__) && !defined(__LP64__)) || defined(_WIN32) || defined(__QNX__)
34
/* This code is public domain -- Will Hartung 4/9/09 */
35
static ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
	char *bufptr = NULL;
	char *p = bufptr;
	size_t size;
	int c;

	if (lineptr == NULL) {
		return -1;
	}
	if (stream == NULL) {
		return -1;
	}
	if (n == NULL) {
		return -1;
	}
	bufptr = *lineptr;
	size = *n;

	c = fgetc(stream);
	if (c == EOF) {
		return -1;
	}
	if (bufptr == NULL) {
		bufptr = malloc(128);
		if (bufptr == NULL) {
			return -1;
		}
		size = 128;
	}
	p = bufptr;
	while(c != EOF) {
66
		size_t curpos = p-bufptr;
67

68
		if (curpos > (size - 1)) {
69 70
			size = size + 128;
			bufptr = realloc(bufptr, size);
71
			p = bufptr + curpos;
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
			if (bufptr == NULL) {
				return -1;
			}
		}
		*p++ = c;
		if (c == '\n') {
			break;
		}
		c = fgetc(stream);
	}

	*p++ = '\0';
	*lineptr = bufptr;
	*n = size;

87
	return (ssize_t)(p - bufptr) - 1;
88 89 90
}
#endif

91
static LinphoneLogCollectionState old_collection_state;
92
static void collect_init(void)  {
93
	old_collection_state = linphone_core_log_collection_enabled();
94
	linphone_core_set_log_collection_path(bc_tester_get_writable_dir_prefix());
95 96
}

97
static void collect_cleanup(LinphoneCoreManager *marie)  {
98 99 100 101 102 103
	linphone_core_manager_destroy(marie);

	linphone_core_enable_log_collection(old_collection_state);
	linphone_core_reset_log_collection();
}

104
static LinphoneCoreManager* setup(LinphoneLogCollectionState log_collection_state)  {
105
	LinphoneCoreManager *marie;
106 107
	int timeout = 300;

108
	collect_init();
109
	linphone_core_enable_log_collection(log_collection_state);
110

111
	marie = linphone_core_manager_new2("marie_rc", 0);
112
	// wait a few seconds to generate some traffic
113 114 115 116
	while (--timeout){
		// Generate some logs - error logs because we must ensure that
		// even if user did not enable logs, we will see them
		ms_error("(test error)Timeout in %d...", timeout);
117 118 119 120
	}
	return marie;
}

121
#if HAVE_ZLIB
122

123
/*returns uncompressed log file*/
124
static FILE* gzuncompress(const char* filepath) {
125 126
		gzFile file = gzopen(filepath, "rb");
		FILE *output = NULL;
127
		FILE *ret;
128
		char *newname = ms_strdup_printf("%s.txt", filepath);
129 130
		char buffer[512]={0};
		output = fopen(newname, "wb");
131
		while (gzread(file, buffer, 511) > 0) {
132 133
			fputs(buffer, output);
			memset(buffer, 0, strlen(buffer));
134
		}
135
		fclose(output);
136
		BC_ASSERT_EQUAL(gzclose(file), Z_OK, int, "%d");
137
		ret=fopen(newname, "rb");
138
		ms_free(newname);
139
		return ret;
140 141 142
}
#endif

143
static time_t get_current_time(void) {
144 145
	struct timeval tp;
	struct tm *lt;
146
#ifndef _WIN32
147 148 149 150 151 152
	struct tm tmbuf;
#endif
	time_t tt;
	ortp_gettimeofday(&tp,NULL);
	tt = (time_t)tp.tv_sec;

153
#ifdef _WIN32
154 155 156 157 158 159 160
	lt = localtime(&tt);
#else
	lt = localtime_r(&tt,&tmbuf);
#endif
	return mktime(lt);
}

161
static time_t check_file(LinphoneCoreManager* mgr)  {
162

163
	time_t cur_time = get_current_time();
164
	char*    filepath = linphone_core_compress_log_collection();
165
	time_t  log_time = -1;
166
	uint32_t timediff = 0;
167
	FILE *file = NULL;
168

169
	BC_ASSERT_PTR_NOT_NULL(filepath);
170

171 172 173 174
	if (filepath != NULL) {
		int line_count = 0;
		char *line = NULL;
		size_t line_size = 256;
175
#ifndef _WIN32
176
		struct tm tm_curr = {0};
177
		time_t time_prev = 0;
178
#endif
179

180 181 182 183
#if HAVE_ZLIB
		// 0) if zlib is enabled, we must decompress the file first
		file = gzuncompress(filepath);
#else
184
		file = fopen(filepath, "rb");
185
#endif
186
		BC_ASSERT_PTR_NOT_NULL(file);
187
		if (!file) return 0;
188
		// 1) expect to find folder name in filename path
189
		BC_ASSERT_PTR_NOT_NULL(strstr(filepath, bc_tester_get_writable_dir_prefix()));
190 191 192

		// 2) check file contents
		while (getline(&line, &line_size, file) != -1) {
193
			// a) there should be at least 25 lines
194
			++line_count;
195
#ifndef _WIN32
196 197 198 199
			// b) logs should be ordered by date (format: 2014-11-04 15:22:12:606)
			if (strlen(line) > 24) {
				char date[24] = {'\0'};
				memcpy(date, line, 23);
200 201
				/*reset tm_curr to reset milliseconds and below fields*/
				memset(&tm_curr, 0, sizeof(struct tm));
202
				if (strptime(date, "%Y-%m-%d %H:%M:%S", &tm_curr) != NULL) {
203 204
					tm_curr.tm_isdst = -1; // LOL
					log_time = mktime(&tm_curr);
205
					BC_ASSERT_GREATER(log_time , time_prev, long int, "%ld");
206
					time_prev = log_time;
207 208
				}
			}
209
#endif
210
		}
211
		BC_ASSERT_GREATER(line_count , 25, int, "%d");
212 213 214
		free(line);
		fclose(file);
		ms_free(filepath);
215

216

217
		timediff = labs((long int)log_time - (long int)cur_time);
218
#ifndef _WIN32
219
		BC_ASSERT_LOWER(timediff, 1, unsigned, "%u");
220
		if( !(timediff <= 1) ){
221 222 223 224 225 226 227 228 229
			char buffers[2][128] = {{0}};
			strftime(buffers[0], sizeof(buffers[0]), "%Y-%m-%d %H:%M:%S", localtime(&log_time));
			strftime(buffers[1], sizeof(buffers[1]), "%Y-%m-%d %H:%M:%S", localtime(&cur_time));

			ms_error("log_time: %ld (%s), cur_time: %ld (%s) timediff: %u"
				, (long int)log_time, buffers[0]
				, (long int)cur_time, buffers[1]
				, timediff
			);
230
		}
231
#else
232
		(void)timediff;
233 234
		ms_warning("strptime() not available for this platform, test is incomplete.");
#endif
235
	}
236
	// return latest time in file
237
	return log_time;
238 239
}

240
static void collect_files_disabled(void)  {
241
	LinphoneCoreManager* marie = setup(LinphoneLogCollectionDisabled);
242
	BC_ASSERT_PTR_NULL(linphone_core_compress_log_collection());
243
	collect_cleanup(marie);
244 245
}

246
static void collect_files_filled(void) {
247
	LinphoneCoreManager* marie = setup(LinphoneLogCollectionEnabled);
248
	check_file(marie);
249
	collect_cleanup(marie);
250 251
}

252
static void collect_files_small_size(void)  {
253
	LinphoneCoreManager* marie = setup(LinphoneLogCollectionEnabled);
254
	linphone_core_set_log_collection_max_file_size(5000);
255
	check_file(marie);
256
	collect_cleanup(marie);
257 258
}

259
static void collect_files_changing_size(void)  {
260
	LinphoneCoreManager* marie = setup(LinphoneLogCollectionEnabled);
261 262
	int waiting = 100;

263
	check_file(marie);
264

265
	linphone_core_set_log_collection_max_file_size(5000);
266 267 268
	// Generate some logs
	while (--waiting) ms_error("(test error)Waiting %d...", waiting);

269
	check_file(marie);
270

271
	collect_cleanup(marie);
272
}
273 274 275
static void logCollectionUploadStateChangedCb(LinphoneCore *lc, LinphoneCoreLogCollectionUploadState state, const char *info) {

	stats* counters = get_stats(lc);
jehan's avatar
jehan committed
276 277 278
	ms_message("lc [%p], logCollectionUploadStateChanged to [%s], info [%s]",lc
																			,linphone_core_log_collection_upload_state_to_string(state)
																			,info);
279 280 281 282 283 284
	switch(state) {
		case LinphoneCoreLogCollectionUploadStateInProgress:
			counters->number_of_LinphoneCoreLogCollectionUploadStateInProgress++;
			break;
		case LinphoneCoreLogCollectionUploadStateDelivered:
			counters->number_of_LinphoneCoreLogCollectionUploadStateDelivered++;
285
			BC_ASSERT_GREATER((int)strlen(info), 0, int, "%d");
286 287 288 289 290 291
			break;
		case LinphoneCoreLogCollectionUploadStateNotDelivered:
			counters->number_of_LinphoneCoreLogCollectionUploadStateNotDelivered++;
			break;
	}
}
292
static void upload_collected_traces(void)  {
293
	if (transport_supported(LinphoneTransportTls)) {
294
		LinphoneCoreManager* marie = setup(LinphoneLogCollectionEnabled);
295
		int waiting = 100;
296 297 298 299
		LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
		linphone_core_cbs_set_log_collection_upload_state_changed(cbs, logCollectionUploadStateChangedCb);
		linphone_core_add_callbacks(marie->lc, cbs);
		linphone_core_cbs_unref(cbs);
300 301 302 303 304

		linphone_core_set_log_collection_max_file_size(5000);
		linphone_core_set_log_collection_upload_server_url(marie->lc,"https://www.linphone.org:444/lft.php");
		// Generate some logs
		while (--waiting) ms_error("(test error)Waiting %d...", waiting);
305
		ms_free(linphone_core_compress_log_collection());
306
		linphone_core_upload_log_collection(marie->lc);
307
		BC_ASSERT_TRUE(wait_for_until(marie->lc,marie->lc,&marie->stat.number_of_LinphoneCoreLogCollectionUploadStateDelivered,1, 10000));
308 309 310

		/*try 2 times*/
		waiting=100;
311
		linphone_core_reset_log_collection();
312
		while (--waiting) ms_error("(test error)Waiting %d...", waiting);
313
		ms_free(linphone_core_compress_log_collection());
314
		linphone_core_upload_log_collection(marie->lc);
315
		BC_ASSERT_TRUE(wait_for_until(marie->lc,marie->lc,&marie->stat.number_of_LinphoneCoreLogCollectionUploadStateDelivered,2, 10000));
316
		collect_cleanup(marie);
317
	}
318
}
319 320

test_t log_collection_tests[] = {
321 322 323 324
	TEST_NO_TAG("No file when disabled", collect_files_disabled),
	TEST_NO_TAG("Collect files filled when enabled", collect_files_filled),
	TEST_NO_TAG("Logs collected into small file", collect_files_small_size),
	TEST_NO_TAG("Logs collected when decreasing max size", collect_files_changing_size),
325
	TEST_NO_TAG("Upload collected traces", upload_collected_traces)
326 327
};

328
test_suite_t log_collection_test_suite = {"LogCollection", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each,
329 330
										  sizeof(log_collection_tests) / sizeof(log_collection_tests[0]),
										  log_collection_tests};