1 /*
2 liblinphone_tester - liblinphone test suite
3 Copyright (C) 2013 Belledonne Communications SARL
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19
20 #include "linphone/core.h"
21 #include "private.h"
22 #include "liblinphone_tester.h"
23
24 #if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
25 #pragma GCC diagnostic push
26 #endif
27 #ifdef _MSC_VER
28 #pragma warning(disable : 4996)
29 #else
30 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
31 #pragma GCC diagnostic ignored "-Wstrict-prototypes"
32 #endif
33
34 #ifdef HAVE_GTK
35 #include <gtk/gtk.h>
36 #endif
37
38 #if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
39 #pragma GCC diagnostic pop
40 #endif
41
42
43 static FILE * log_file = NULL;
44
45 #ifdef __ANDROID__
46
47 #include <android/log.h>
48 #include <jni.h>
49 #define CALLBACK_BUFFER_SIZE 1024
50
51 static JNIEnv *current_env = NULL;
52 static jobject current_obj = 0;
53 static const char* LogDomain = "liblinphone_tester";
54
55 int main(int argc, char** argv);
56
liblinphone_android_log_handler(int prio,const char * fmt,va_list args)57 void liblinphone_android_log_handler(int prio, const char *fmt, va_list args) {
58 char str[4096];
59 char *current;
60 char *next;
61
62 vsnprintf(str, sizeof(str) - 1, fmt, args);
63 str[sizeof(str) - 1] = '\0';
64 if (strlen(str) < 512) {
65 __android_log_write(prio, LogDomain, str);
66 } else {
67 current = str;
68 while ((next = strchr(current, '\n')) != NULL) {
69 *next = '\0';
70 __android_log_write(prio, LogDomain, current);
71 current = next + 1;
72 }
73 __android_log_write(prio, LogDomain, current);
74 }
75 }
76
liblinphone_android_ortp_log_handler(const char * domain,OrtpLogLevel lev,const char * fmt,va_list args)77 static void liblinphone_android_ortp_log_handler(const char *domain, OrtpLogLevel lev, const char *fmt, va_list args) {
78 int prio;
79 switch(lev){
80 case ORTP_DEBUG: prio = ANDROID_LOG_DEBUG; break;
81 case ORTP_MESSAGE: prio = ANDROID_LOG_INFO; break;
82 case ORTP_WARNING: prio = ANDROID_LOG_WARN; break;
83 case ORTP_ERROR: prio = ANDROID_LOG_ERROR; break;
84 case ORTP_FATAL: prio = ANDROID_LOG_FATAL; break;
85 default: prio = ANDROID_LOG_DEFAULT; break;
86 }
87 liblinphone_android_log_handler(prio, fmt, args);
88 }
89
liblinphone_android_bctbx_log_handler(const char * domain,BctbxLogLevel lev,const char * fmt,va_list args)90 static void liblinphone_android_bctbx_log_handler(const char *domain, BctbxLogLevel lev, const char *fmt, va_list args) {
91 int prio;
92 switch(lev){
93 case BCTBX_LOG_DEBUG: prio = ANDROID_LOG_DEBUG; break;
94 case BCTBX_LOG_MESSAGE: prio = ANDROID_LOG_INFO; break;
95 case BCTBX_LOG_WARNING: prio = ANDROID_LOG_WARN; break;
96 case BCTBX_LOG_ERROR: prio = ANDROID_LOG_ERROR; break;
97 case BCTBX_LOG_FATAL: prio = ANDROID_LOG_FATAL; break;
98 default: prio = ANDROID_LOG_DEFAULT; break;
99 }
100 liblinphone_android_log_handler(prio, fmt, args);
101 }
102
bcunit_android_trace_handler(int level,const char * fmt,va_list args)103 void bcunit_android_trace_handler(int level, const char *fmt, va_list args) {
104 char buffer[CALLBACK_BUFFER_SIZE];
105 jstring javaString;
106 jclass cls;
107 jmethodID method;
108 jint javaLevel = level;
109 JNIEnv *env = current_env;
110 if(env == NULL) return;
111 vsnprintf(buffer, CALLBACK_BUFFER_SIZE, fmt, args);
112 javaString = (*env)->NewStringUTF(env, buffer);
113 cls = (*env)->GetObjectClass(env, current_obj);
114 method = (*env)->GetMethodID(env, cls, "printLog", "(ILjava/lang/String;)V");
115 (*env)->CallVoidMethod(env, current_obj, method, javaLevel, javaString);
116 (*env)->DeleteLocalRef(env,javaString);
117 (*env)->DeleteLocalRef(env,cls);
118 }
119
Java_org_linphone_tester_Tester_run(JNIEnv * env,jobject obj,jobjectArray stringArray)120 JNIEXPORT jint JNICALL Java_org_linphone_tester_Tester_run(JNIEnv *env, jobject obj, jobjectArray stringArray) {
121 int i, ret;
122 int argc = (*env)->GetArrayLength(env, stringArray);
123 char **argv = (char**) malloc(sizeof(char*) * argc);
124
125 for (i=0; i<argc; i++) {
126 jstring string = (jstring) (*env)->GetObjectArrayElement(env, stringArray, i);
127 const char *rawString = (const char *) (*env)->GetStringUTFChars(env, string, 0);
128 argv[i] = strdup(rawString);
129 (*env)->ReleaseStringUTFChars(env, string, rawString);
130 }
131 current_env = env;
132 current_obj = obj;
133 bc_set_trace_handler(bcunit_android_trace_handler);
134 ret = main(argc, argv);
135 current_env = NULL;
136 bc_set_trace_handler(NULL);
137 for (i=0; i<argc; i++) {
138 free(argv[i]);
139 }
140 free(argv);
141 return ret;
142 }
143
Java_org_linphone_tester_Tester_keepAccounts(JNIEnv * env,jclass c,jboolean keep)144 JNIEXPORT void JNICALL Java_org_linphone_tester_Tester_keepAccounts(JNIEnv *env, jclass c, jboolean keep) {
145 liblinphone_tester_keep_accounts((int)keep);
146 }
147
Java_org_linphone_tester_Tester_clearAccounts(JNIEnv * env,jclass c)148 JNIEXPORT void JNICALL Java_org_linphone_tester_Tester_clearAccounts(JNIEnv *env, jclass c) {
149 liblinphone_tester_clear_accounts();
150 }
151 #endif /* __ANDROID__ */
152
log_handler(int lev,const char * fmt,va_list args)153 static void log_handler(int lev, const char *fmt, va_list args) {
154 #ifdef _WIN32
155 vfprintf(lev == ORTP_ERROR ? stderr : stdout, fmt, args);
156 fprintf(lev == ORTP_ERROR ? stderr : stdout, "\n");
157 #else
158 va_list cap;
159 va_copy(cap,args);
160 #ifdef __ANDROID__
161 /* IMPORTANT: needed by liblinphone tester to retrieve suite list...*/
162 bcunit_android_trace_handler(lev == ORTP_ERROR, fmt, cap);
163 #else
164 /* Otherwise, we must use stdio to avoid log formatting (for autocompletion etc.) */
165 vfprintf(lev == ORTP_ERROR ? stderr : stdout, fmt, cap);
166 fprintf(lev == ORTP_ERROR ? stderr : stdout, "\n");
167 #endif
168 va_end(cap);
169 #endif
170 if (log_file){
171 ortp_logv_out(ORTP_LOG_DOMAIN, lev, fmt, args);
172 }
173 }
174
liblinphone_tester_init(void (* ftester_printf)(int level,const char * fmt,va_list args))175 void liblinphone_tester_init(void(*ftester_printf)(int level, const char *fmt, va_list args)) {
176 if (! log_file) {
177 #if defined(__ANDROID__)
178 linphone_core_set_log_handler(liblinphone_android_ortp_log_handler);
179 bctbx_set_log_handler(liblinphone_android_bctbx_log_handler);
180 #endif
181 }
182
183 if (ftester_printf == NULL) ftester_printf = log_handler;
184 bc_tester_init(ftester_printf, ORTP_MESSAGE, ORTP_ERROR, "rcfiles");
185 liblinphone_tester_add_suites();
186 }
187
liblinphone_tester_set_log_file(const char * filename)188 int liblinphone_tester_set_log_file(const char *filename) {
189 if (log_file) {
190 fclose(log_file);
191 }
192 log_file = fopen(filename, "w");
193 if (!log_file) {
194 ms_error("Cannot open file [%s] for writing logs because [%s]", filename, strerror(errno));
195 return -1;
196 }
197 ms_message("Redirecting traces to file [%s]", filename);
198 bctbx_set_log_file(log_file);
199 ortp_set_log_file(log_file);
200 return 0;
201 }
202
203
204 #if !TARGET_OS_IPHONE && !(defined(LINPHONE_WINDOWS_PHONE) || defined(LINPHONE_WINDOWS_UNIVERSAL))
205
206 static const char* liblinphone_helper =
207 "\t\t\t--verbose\n"
208 "\t\t\t--silent\n"
209 "\t\t\t--log-file <output log file path>\n"
210 "\t\t\t--domain <test sip domain>\n"
211 "\t\t\t--auth-domain <test auth domain>\n"
212 "\t\t\t--dns-hosts </etc/hosts -like file to used to override DNS names (default: tester_hosts)>\n"
213 "\t\t\t--keep-recorded-files\n"
214 "\t\t\t--disable-leak-detector\n"
215 "\t\t\t--disable-tls-support\n"
216 "\t\t\t--no-ipv6 (turn off IPv6 in LinphoneCore, tests requiring IPv6 will be skipped)\n"
217 "\t\t\t--show-account-manager-logs (show temporary test account creation logs)\n"
218 ;
219
main(int argc,char * argv[])220 int main (int argc, char *argv[])
221 {
222 int i;
223 int ret;
224
225 #ifdef HAVE_GTK
226 gtk_init(&argc, &argv);
227 #if !GLIB_CHECK_VERSION(2,32,0) // backward compatibility with Debian 6 and CentOS 6
228 g_thread_init(NULL);
229 #endif
230 gdk_threads_init();
231 #endif
232
233 liblinphone_tester_init(NULL);
234 linphone_core_set_log_level(ORTP_ERROR);
235
236 for(i = 1; i < argc; ++i) {
237 if (strcmp(argv[i], "--verbose") == 0) {
238 linphone_core_set_log_level(ORTP_MESSAGE);
239 } else if (strcmp(argv[i], "--silent") == 0) {
240 linphone_core_set_log_level(ORTP_FATAL);
241 } else if (strcmp(argv[i],"--log-file")==0){
242 CHECK_ARG("--log-file", ++i, argc);
243 if (liblinphone_tester_set_log_file(argv[i]) < 0) return -2;
244 } else if (strcmp(argv[i],"--domain")==0){
245 CHECK_ARG("--domain", ++i, argc);
246 test_domain=argv[i];
247 } else if (strcmp(argv[i],"--auth-domain")==0){
248 CHECK_ARG("--auth-domain", ++i, argc);
249 auth_domain=argv[i];
250 }else if (strcmp(argv[i],"--dns-hosts")==0){
251 CHECK_ARG("--dns-hosts", ++i, argc);
252 userhostsfile=argv[i];
253 } else if (strcmp(argv[i],"--keep-recorded-files")==0){
254 liblinphone_tester_keep_recorded_files(TRUE);
255 } else if (strcmp(argv[i],"--disable-leak-detector")==0){
256 liblinphone_tester_disable_leak_detector(TRUE);
257 } else if (strcmp(argv[i],"--disable-tls-support")==0){
258 liblinphone_tester_tls_support_disabled = TRUE;
259 } else if (strcmp(argv[i],"--no-ipv6")==0){
260 liblinphonetester_ipv6 = FALSE;
261 } else if (strcmp(argv[i],"--show-account-manager-logs")==0){
262 liblinphonetester_show_account_manager_logs=TRUE;
263 } else {
264 int bret = bc_tester_parse_args(argc, argv, i);
265 if (bret>0) {
266 i += bret - 1;
267 continue;
268 } else if (bret<0) {
269 bc_tester_helper(argv[0], liblinphone_helper);
270 }
271 return bret;
272 }
273 }
274
275 ret = bc_tester_start(argv[0]);
276 liblinphone_tester_uninit();
277 return ret;
278 }
279
280
281 #endif
282