1 /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2  * Copyright (C) 2021  Frediano Ziglio
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 
20 /*
21  * Check log elision implementation
22  */
23 #include "common.h"
24 #include <assert.h>
25 #include <freetds/utils.h>
26 
27 #if HAVE_UNISTD_H
28 #undef getpid
29 #include <unistd.h>
30 #endif /* HAVE_UNISTD_H */
31 
32 enum {
33 	LOOP = 100,
34 	THREADS = 3,
35 };
36 
TDS_THREAD_PROC_DECLARE(log_func,idx_ptr)37 static TDS_THREAD_PROC_DECLARE(log_func, idx_ptr)
38 {
39 	const int idx = TDS_PTR2INT(idx_ptr);
40 	const char letter = 'A' + idx;
41 	TDSDUMP_OFF_ITEM off_item;
42 	int n = idx, i;
43 
44 	/* LOOP times */
45 	for (i = 0; i < LOOP; ++i) {
46 		/* send log */
47 		tdsdump_log(TDS_DBG_ERROR, "Some log from %c number %d\n", letter, n);
48 
49 		/* wait 1-10 ms */
50 		tds_sleep_ms((rand() % 10) + 1);
51 
52 		/* disable logs */
53 		tdsdump_off(&off_item);
54 
55 		/* send wrong log */
56 		tdsdump_log(TDS_DBG_ERROR, "Disabled log %c number %d\n", letter, n);
57 
58 		/* wait 1-10 ms */
59 		tds_sleep_ms((rand() % 10) + 1);
60 
61 		/* enable logs */
62 		tdsdump_on(&off_item);
63 
64 		n += 3;
65 	}
66 
67 	return TDS_THREAD_RESULT(0);
68 }
69 
70 int
main(int argc,char ** argv)71 main(int argc, char **argv)
72 {
73 	int i, ret;
74 	tds_thread threads[THREADS];
75 	FILE *f;
76 	char line[1024];
77 	int wrong_lines = 0;
78 	int nexts[THREADS];
79 
80 	tds_debug_flags = TDS_DBGFLAG_ALL | TDS_DBGFLAG_SOURCE;
81 
82 	/* remove file */
83 	unlink("log_elision.out");
84 
85 	/* set output file */
86 	tdsdump_open("log_elision.out");
87 
88 	/* THREADS thread */
89 	for (i = 0; i < THREADS; ++i) {
90 		nexts[i] = i;
91 	}
92 	for (i = 1; i < THREADS; ++i) {
93 		ret = tds_thread_create(&threads[i], log_func, TDS_INT2PTR(i));
94 		assert(ret == 0);
95 	}
96 	log_func(TDS_INT2PTR(0));
97 	for (i = 1; i < THREADS; ++i) {
98 		ret = tds_thread_join(threads[i], NULL);
99 		assert(ret == 0);
100 	}
101 
102 	/* close logs */
103 	tdsdump_close();
104 
105 	/* open logs to read */
106 	f = fopen("log_elision.out", "r");
107 	assert(f != NULL);
108 
109 	/* read line by line */
110 	while (fgets(line, sizeof(line), f) != NULL) {
111 		char thread_letter;
112 		int num_line, num, idx;
113 
114 		/* ignore some start lines */
115 		if (strstr(line, "log_elision.c") == NULL) {
116 			assert(++wrong_lines < 4);
117 			continue;
118 		}
119 
120 		ret = sscanf(line, "log_elision.c:%d:Some log from %c number %d\n",
121 			     &num_line, &thread_letter, &num);
122 		assert(ret == 3);
123 
124 		/* detect number of thread */
125 		assert(thread_letter >= 'A' && thread_letter < 'A' + THREADS);
126 		idx = thread_letter - 'A';
127 
128 		/* check number inside string match the next */
129 		assert(num == nexts[idx]);
130 		nexts[idx] += 3;
131 	}
132 	fclose(f);
133 	f = NULL;
134 
135 	/* check we got all numbers */
136 	for (i = 0; i < THREADS; ++i) {
137 		assert(nexts[i] == i + LOOP * 3);
138 	}
139 
140 	/* cleanup file */
141 	unlink("log_elision.out");
142 
143 	return 0;
144 }
145